Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/304.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 为什么'a==x或y或z'的计算结果总是为真?_Python_Boolean_Boolean Expression - Fatal编程技术网

Python 为什么'a==x或y或z'的计算结果总是为真?

Python 为什么'a==x或y或z'的计算结果总是为真?,python,boolean,boolean-expression,Python,Boolean,Boolean Expression,我正在编写一个安全系统,拒绝未经授权的用户访问 name=input(“您好,请输入您的姓名:”) 如果名称==“Kevin”或“Jon”或“Inbar”: 打印(“已授予访问权限”) 其他: 打印(“访问被拒绝”) 它按预期授予授权用户访问权限,但也允许未经授权的用户进入 你好。请输入您的姓名:鲍勃 允许访问。 为什么会发生这种情况?我已经明确声明,只有当name等于Kevin、Jon或Inbar时,才允许访问。我也尝试过相反的逻辑,如果“Kevin”或“Jon”或“Inbar”==nam

我正在编写一个安全系统,拒绝未经授权的用户访问

name=input(“您好,请输入您的姓名:”)
如果名称==“Kevin”或“Jon”或“Inbar”:
打印(“已授予访问权限”)
其他:
打印(“访问被拒绝”)
它按预期授予授权用户访问权限,但也允许未经授权的用户进入

你好。请输入您的姓名:鲍勃 允许访问。 为什么会发生这种情况?我已经明确声明,只有当
name
等于Kevin、Jon或Inbar时,才允许访问。我也尝试过相反的逻辑,
如果“Kevin”或“Jon”或“Inbar”==name
,但结果是一样的

注意:此问题旨在作为这一常见问题的标准重复目标。还有一个流行的问题也有同样的基本问题,但比较目标是相反的。此问题不应与此问题重复,因为Python新手可能会遇到此问题,他们可能很难将反向问题中的知识应用到他们的问题中。


在许多情况下,Python的外观和行为类似于自然英语,但这是抽象失败的一种情况。人们可以使用上下文线索来确定“Jon”和“Inbar”是连接到动词“equals”的对象,但Python解释器更注重文字

if name == "Kevin" or "Jon" or "Inbar":
逻辑上等同于:

if (name == "Kevin") or ("Jon") or ("Inbar"):
if (False) or ("Jon") or ("Inbar"):
对于用户Bob,这相当于:

if (name == "Kevin") or ("Jon") or ("Inbar"):
if (False) or ("Jon") or ("Inbar"):
运算符选择第一个带正数的参数:

由于“Jon”具有正真值,因此执行
if
块。这就是为什么不管给定的名称如何,都会打印“已授予访问权限”

如果“Kevin”或“Jon”或“Inbar”==name,所有这些推理也适用于表达式
。第一个值,
“Kevin”
,为true,因此执行
if


有两种常见的方法可以正确构造此条件

  • 使用多个
    ==
    运算符显式检查每个值:

    if name == "Kevin" or name == "Jon" or name == "Inbar":
    
  • 组成有效值的集合(例如集合、列表或元组),并使用
    in
    运算符测试成员资格:

    if name in {"Kevin", "Jon", "Inbar"}:
    
  • 一般而言,应优先选择第二种,因为它更容易阅读,也更快:

    >>> import timeit
    >>> timeit.timeit('name == "Kevin" or name == "Jon" or name == "Inbar"',
        setup="name='Inbar'")
    0.4247764749999945
    >>> timeit.timeit('name in {"Kevin", "Jon", "Inbar"}', setup="name='Inbar'")
    0.18493307199999265
    

    对于那些想要证明a==b或c或d或e:…
    确实是这样解析的人来说。内置的
    ast
    模块提供了一个答案:

    >>> import ast
    >>> ast.parse("a == b or c or d or e", "<string>", "eval")
    <ast.Expression object at 0x7f929c898220>
    >>> print(ast.dump(_, indent=4))
    Expression(
        body=BoolOp(
            op=Or(),
            values=[
                Compare(
                    left=Name(id='a', ctx=Load()),
                    ops=[
                        Eq()],
                    comparators=[
                        Name(id='b', ctx=Load())]),
                Name(id='c', ctx=Load()),
                Name(id='d', ctx=Load()),
                Name(id='e', ctx=Load())]))
    
    导入ast >>>ast.parse(“a==b或c或d或e”,“eval”) >>>打印(ast.dump(u,缩进=4)) 表情( body=BoolOp( op=或(), 价值观=[ 比较( 左=名称(id='a',ctx=Load()), 老年退休金=[ Eq()], 比较器=[ 名称(id='b',ctx=Load())], 名称(id='c',ctx=Load()), 名称(id='d',ctx=Load()), 名称(id='e',ctx=Load())])
    可以看出,它是应用于四个子表达式的布尔运算符
    :比较
    a==b
    ;和简单的表达式
    c
    d
    ,和
    e
    ,简单的工程问题,让我们再简单一点

    In [1]: a,b,c,d=1,2,3,4
    In [2]: a==b
    Out[2]: False
    
    但是,Python继承了C语言,将非零整数的逻辑值计算为True

    In [11]: if 3:
        ...:     print ("yey")
        ...:
    yey
    
    现在,Python构建在该逻辑的基础上,并允许您使用逻辑文本,例如或整数,等等

    In [9]: False or 3
    Out[9]: 3
    
    最后

    In [4]: a==b or c or d
    Out[4]: 3
    
    正确的书写方式是:

    In [13]: if a in (b,c,d):
        ...:     print('Access granted')
    

    为了安全起见,我还建议您不要硬编码密码。

    如果name==“Kevin”或“Jon”或“Inbar”,则在
    中有3个条件检查:

    • 姓名==“凯文”
    • “乔恩”
    • “Inbar”
    这个if语句等价于

    if name == "Kevin":
        print("Access granted.")
    elif "Jon":
        print("Access granted.")
    elif "Inbar":
        print("Access granted.")
    else:
        print("Access denied.")
    
    由于
    elif“Jon”
    始终为真,因此授予任何用户访问权限

    解决方案
    您可以使用下面的任何一种方法

    快速

    if name in ["Kevin", "Jon", "Inbar"]:
        print("Access granted.")
    else:
        print("Access denied.")
    

    if name == "Kevin" or name == "Jon" or name == "Inbar":
        print("Access granted.")
    else:
        print("Access denied.")
    
    缓慢+不必要的代码

    if name == "Kevin":
        print("Access granted.")
    elif name == "Jon":
        print("Access granted.")
    elif name == "Inbar":
        print("Access granted.")
    else:
        print("Access denied.")
    
    非空列表、集合、字符串等是可计算的,因此返回True。 因此,当你说:

    a = "Raul"
    if a == "Kevin" or "John" or "Inbar":
        pass
    
    你实际上是在说:

    if "Raul" == "Kevin" or "John" != "" or "Inbar" != "":
        pass
    
    因为“John”和“Inbar”中至少有一个不是空字符串,所以整个表达式始终返回True

    解决方案: 或:

    方法 数据科学家如何处理这个问题 最简单的方法是不需要比较运算符,而是使用列表。这在安全系统上看起来令人印象深刻,因为您学会了访问ORMs

    user = input("Enter name: ")
    
    if user in {"Bob", "Kevin", "Joe"}:
       print("Access granted, " + str(user) + ".")
    else:
       print("Access denied.")
    
    或者,您可以使用与上面完全相同的代码,只需将注册用户列表放入他们自己的列表中:

    user = input("Enter name: ")
    users = {"Bob", "Kevin", "Joe", "a million more users if you like"}
    
    if user in users:
       print("Access granted, " + str(user) + ".")
    else:
       print("Access denied.")
    
    如果希望安全地完成此协议而不存在攻击风险,请设置双参数。这将检查迷你ORM中的
    第一个
    最后一个
    名称字段,以及
    密码
    秘密问题
    密钥。如果要在不进行散列的情况下高效地延迟加载用户凭据,可以按如下方式对对象进行排序:

    def lazy(i):
       j = 0 # For example
       while j < i:
          yield j
          j += 1
    
    这个问题可以从任何角度来解决:内存管理、安全性,或者仅仅通过一个有机列表或打包的ORM


    希望这能有所帮助。

    @Jean François FYI早些时候在python会议室讨论了这个问题及其dupe目标。我知道如果你想关闭它,但我想你可能想知道该帖子最近重新开放的原因。充分披露:Martijn,关于dupe target的答案的作者还没有来得及插话。Martijn的答案很好地解释了“不要使用自然语言”,其他人,嗯。。。那是辉煌的投票时代。。。下面的答案只是重复了这一点。对我来说,它是复制品。但是如果Martijn选择重新打开,我不介意。这个问题的变体包括
    x或y在z
    x和y在z
    x=
    
    def lazy(i):
       j = 0 # For example
       while j < i:
          yield j
          j += 1
    
    for j in lazy_range(10):
       do_something_here(j)