在许多情况下,Python 的外观和行为都与自然英语相似,但在这种情况下,这种抽象就失效了。人们可以使用上下文线索来确定“Jon”和“Inbar”是与动词“equals”连接的对象,但 Python 解释器更注重字面意思。
if name == "Kevin" or "Jon" or "Inbar":
在逻辑上等同于:
if (name == "Kevin") or ("Jon") or ("Inbar"):
对于用户 Bob 来说,这相当于:
if (False) or ("Jon") or ("Inbar"):
该 or
运算符 选择第一个 为 “真”的 ,也就是说,它将 would satisfy an if
condition (如果所有操作数都不是“真”,则选择最后一个操作数):
if "Jon":
由于 \'Jon\' 为真,因此 if
执行该块。这就是导致无论给出什么名称都会打印 \'Access grant\' 的原因。
所有这些推理也适用于表达式 if "Kevin" or "Jon" or "Inbar" == name
。第一个值 "Kevin"
是真,因此该 if
块执行。
有三种常见的方法可以正确构造此条件。
-
p7
if name == "Kevin" or name == "Jon" or name == "Inbar":
-
p8
if name in {"Kevin", "Jon", "Inbar"}:
-
p9
if any(name == auth for auth in ["Kevin", "Jon", "Inbar"]):
一般来说,应该优先选择第二种,因为它更容易阅读,也更快:
>>> import timeit
>>> timeit.timeit('name == "Kevin" or name == "Jon" or name == "Inbar"',
setup="name='Inbar'")
0.0960568820592016
>>> timeit.timeit('name in {"Kevin", "Jon", "Inbar"}', setup="name='Inbar'")
0.034957461059093475
>>> timeit.timeit('any(name == auth for auth in ["Kevin", "Jon", "Inbar"])',
setup="name='Inbar'")
0.6511583919636905
对于那些想要证明 if a == b or c or d or 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())]))
可以看出,它是 or
应用于四个子表达式的布尔运算符:比较 a == b
;和简单表达式 c
, d
,以及 e
.