当前位置: 首页 > 知识库问答 >
问题:

为什么`A==b或c或D`的计算结果总是为真?[副本]

宋臻
2023-03-14

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

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

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

Hello. Please enter your name:
Bob
Access granted.

为什么会出现这种情况?我已经明确声明,只有当name等于Kevin、Jon或inbar时才授予访问权限。我也尝试过相反的逻辑如果“kevin”或“jon”或“inbar”==name,但结果是一样的。

共有1个答案

凌俊名
2023-03-14

在许多情况下,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"):

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

if ("Jon"):

并且由于“jon”具有正真值,因此执行if块。这就是为什么无论给出的名称是什么,“授予的访问权限”都要打印出来的原因。

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

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

>

  • 使用多个==运算符对每个值进行显式检查:
    如果name==“kevin”或name==“jon”或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
    

    对于那些可能想要证明if a==b或c或d或e:...确实是这样解析的。内置的AST模块提供了一个答案:

    >>> import ast
    >>> ast.parse("if a == b or c or d or e: ...")
    <_ast.Module object at 0x1031ae6a0>
    >>> ast.dump(_)
    "Module(body=[If(test=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())]), body=[Expr(value=Ellipsis())], orelse=[])])"
    >>>
    

    因此if语句的test如下所示:

    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())
     ]
    )
    

    可以看到,它是应用于多个的布尔运算符,即A==BCDE

  •  类似资料:
    • 问题内容: 我正在编写一个拒绝访问未授权用户的安全系统。 它可以按预期授予授权用户访问权限,但也允许未经授权的用户使用! 为什么会发生这种情况?我已经明确指出仅在name等于,或 时才授予访问权限。我也尝试过相反的逻辑if ,但是结果是一样的。 问题答案: 在许多情况下,Python的外观和行为都像自然的英语,但这是这种抽象失败的一种情况。人们可以使用上下文线索来确定和是与动词连接的对象,但是Py

    • 我正在编写一个安全系统,拒绝未经授权的用户访问。 它按预期授予授权用户访问权限,但也允许未经授权的用户进入! 为什么会发生这种情况?我已经明确声明,只有当等于Kevin、Jon或Inbar时,才允许访问。我也尝试过相反的逻辑,,但结果是一样的。 注意:这个问题旨在作为这个非常常见的问题的规范重复目标。还有另一个热门问题如何针对单个值测试多个变量?这有同样的基本问题,但比较目标是相反的。这个问题不应

    • 问题内容: 我尝试了一些代码,使用XOR在Java中交换两个整数而不使用第三个变量。 这是我尝试的两个交换函数: 这段代码产生的输出是这样的: 我很好奇,为什么这样说: 与这个不同吗? 问题答案: 问题是评估的顺序: 参见JLS第15.26.2节 首先,对左操作数求值以产生一个变量。 如果该评估突然完成,则赋值表达式由于相同的原因而突然完成;右边的操作数不会被评估,并且不会发生赋值。 否则,将保存

    • 问题内容: 我有一个可以接收零或三个命令行参数的python脚本。(要么以默认行为运行,要么需要指定所有三个值。) 诸如此类的理想语法是什么? ? 问题答案: 如果您要使用的是最小形式,请执行以下操作: 这将翻译您的问题的标题。 更新:正如Volatility and Supr正确地说的那样,您可以应用De Morgan的定律并获得等效的: 我的建议是使用对您和其他程序员更重要的形式。第一个意思是

    • 然而,今天我在处理一些代码时,意外地发现以下两个交换给出了不同的结果: 这让我难以置信。有人能给我解释一下这里发生了什么吗?

    • 我尝试了一些代码在Java中交换两个整数,而不使用第三个变量,即使用XOR。 以下是我尝试的两个交换函数: 该代码产生的输出如下: 我很想知道,为什么会有这样的说法: 和这个不一样?