Python 为什么`a == b or c or d` 总是评估为真?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20002503/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 19:14:02  来源:igfitidea点击:

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

pythonbooleanboolean-expression

提问by Kevin

I am writing a security system that denies access to unauthorized users.

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

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.")

It grants access to authorized users as expected, but it also lets in unauthorized users!

它按预期向授权用户授予访问权限,但也允许未经授权的用户进入!

Hello. Please enter your name:
Bob
Access granted.

Why does this occur? I've plainly stated to only grant access when nameequals Kevin, Jon, or Inbar. I have also tried the opposite logic, if "Kevin" or "Jon" or "Inbar" == name, but the result is the same.

为什么会出现这种情况?我已经明确声明只在name等于 Kevin、Jon 或 Inbar时授予访问权限。我也尝试过相反的逻辑if "Kevin" or "Jon" or "Inbar" == name,但结果是一样的。

回答by Kevin

In many cases, Python looks and behaves like natural English, but this is one case where that abstraction fails. People can use context clues to determine that "Jon" and "Inbar" are objects joined to the verb "equals", but the Python interpreter is more literal minded.

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

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

is logically equivalent to:

在逻辑上等同于:

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

Which, for user Bob, is equivalent to:

对于用户 Bob,这相当于:

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

The oroperator chooses the first argument with a positive truth value:

or运营商选择以积极的第一个参数真值

if ("Jon"):

And since "Jon" has a positive truth value, the ifblock executes. That is what causes "Access granted" to be printed regardless of the name given.

并且由于“Jon”具有正真值,因此if块会执行​​。这就是导致无论给出的名称如何都会打印“授予访问权限”的原因。

All of this reasoning also applies to the expression if "Kevin" or "Jon" or "Inbar" == name. the first value, "Kevin", is true, so the ifblock executes.

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



There are two common ways to properly construct this conditional.

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

  1. Use multiple ==operators to explicitly check against each value:
    if name == "Kevin" or name == "Jon" or name == "Inbar":

  2. Compose a sequence of valid values, and use the inoperator to test for membership:
    if name in {"Kevin", "Jon", "Inbar"}:

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

  2. 组成一系列有效值,并使用in运算符来测试成员资格:
    if name in {"Kevin", "Jon", "Inbar"}:

In general of the two the second should be preferred as it's easier to read and also faster:

一般来说,第二个应该是首选,因为它更容易阅读,也更快:

>>> 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

回答by user1854182

Simple engineering problem, let's simply it a bit further.

简单的工程问题,让我们再深入一点。

In [1]: a,b,c,d=1,2,3,4
In [2]: a==b
Out[2]: False

But, inherited from the language C, Python evaluates the logical value of a non zero integer as True.

但是,继承自 C 语言,Python 将非零整数的逻辑值计算为 True。

In [11]: if 3:
    ...:     print ("yey")
    ...:
yey

Now, Python builds on that logic and let you use logic literals such as or on integers, and so

现在,Python 建立在该逻辑之上,并允许您使用逻辑文字,例如 或 整数,等等

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

Finally

最后

In [4]: a==b or c or d
Out[4]: 3

The proper way to write it would be:

正确的写法是:

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

For safety I'd also suggest you don't hard code passwords.

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