关于python:为什么’a==b或c或d’总是计算为true?

Why does `a == b or c or d` always evaluate to True?

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

1
2
3
4
5
6
7
8
import sys

print("Hello. Please enter your name:")
name = sys.stdin.readline().strip()
if name =="Kevin" or"Jon" or"Inbar":
    print("Access granted.")
else:
    print("Access denied.")

它按预期授予授权用户访问权限,但也允许未授权用户访问!

1
2
3
Hello. Please enter your name:
Bob
Access granted.

为什么会发生这种情况?我明确表示,只有当name等于kevin、jon或inbar时,才允许访问。我也试过相反的逻辑,if"Kevin" or"Jon" or"Inbar" == name,但结果是一样的。


在许多情况下,Python的外观和行为都像自然的英语,但这是抽象失败的一个例子。人们可以使用上下文线索来确定"jon"和"inbar"是与动词"equals"连接的对象,但python解释器更注重文字。

1
if name =="Kevin" or"Jon" or"Inbar":

逻辑上等同于:

1
if (name =="Kevin") or ("Jon") or ("Inbar"):

对于用户bob,它相当于:

1
if (False) or ("Jon") or ("Inbar"):

or运算符选择具有正真值的第一个参数:

1
if ("Jon"):

由于"jon"具有正真值,因此执行if块。这就是为什么"授权访问"会被打印出来,而不管给出的名称是什么。

所有这些推理也适用于if"Kevin" or"Jon" or"Inbar" == name的表达式。第一个值"Kevin"为真,因此执行if块。

正确构造这个条件有两种常见的方法。

  • 使用多个==运算符显式检查每个值:if name =="Kevin" or name =="Jon" or name =="Inbar":

  • 组成有效值序列,并使用in运算符测试成员身份:if name in ("Kevin","Jon","Inbar"):

  • 一般来说,第二个更容易阅读,也更快:

    1
    2
    3
    4
    5
    6
    7
    In [1]: name ="Inbar"

    In [2]: %timeit name =="Kevin" or name =="Jon" or name =="Inbar"
    10000000 loops, best of 3: 116 ns per loop

    In [3]: %timeit name in ("Kevin","Jon","Inbar")
    10000000 loops, best of 3: 65.2 ns per loop