<p>在许多情况下,Python的外观和行为类似于自然英语,但这是抽象失败的一种情况。人们可以使用上下文线索来确定“Jon”和“Inbar”是连接到动词“equals”的对象,但Python解释器更注重文字</p>
<pre><code>if name == "Kevin" or "Jon" or "Inbar":
</code></pre>
<p>逻辑上等同于:</p>
<pre><code>if (name == "Kevin") or ("Jon") or ("Inbar"):
</code></pre>
<p>对于用户Bob,这相当于:</p>
<pre><code>if (False) or ("Jon") or ("Inbar"):
</code></pre>
<p><code>or</code>运算符选择第一个带有正<a href="http://docs.python.org/3/library/stdtypes.html#truth-value-testing" rel="noreferrer">truth value</a>的参数:</p>
<pre><code>if "Jon":
</code></pre>
<p>由于“Jon”具有正真值,因此执行<code>if</code>块。这就是为什么不管给定的名称如何,都会打印“已授予访问权限”</p>
<p>所有这些推理也适用于表达式<code>if "Kevin" or "Jon" or "Inbar" == name</code>。第一个值<code>"Kevin"</code>为true,因此执行<code>if</code>块</p>
<hr/>
<p>有两种常见的方法可以正确构造此条件</p>
<ol>
<li><p>使用多个<code>==</code>运算符显式检查每个值:</p>
<pre><code>if name == "Kevin" or name == "Jon" or name == "Inbar":
</code></pre>
</li>
<li><p>组成有效值的集合(例如集合、列表或元组),并使用<code>in</code>运算符测试成员资格:</p>
<pre><code>if name in {"Kevin", "Jon", "Inbar"}:
</code></pre>
</li>
</ol>
<p>一般而言,应优先选择第二种,因为它更容易阅读,也更快:</p>
<pre><code>>>> 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
</code></pre>
<hr/>
<p>对于那些想要证明<code>if a == b or c or d or e: ...</code>确实是这样解析的人。内置的<code>ast</code>模块提供了一个答案:</p>
<pre><code>>>> 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())]))
</code></pre>
<p>可以看到,布尔运算符<code>or</code>应用于四个子表达式:比较<code>a == b</code>;和简单表达式<code>c</code>、<code>d</code>和<code>e</code></p>