【问题标题】:Python: How to chain boolean tests to get False as soon as it gets the first FalsePython:如何在获得第一个 False 后立即链接布尔测试以获取 False
【发布时间】:2012-04-27 18:35:49
【问题描述】:

在尝试减少嵌套 ifs(以及停止工作的脚本)遇到很多麻烦之后,我意识到我可能对布尔值在 python 中的工作原理和工作方式有错误的想法。

我有这个(工作正常但扭曲):

if (not gotside):
    if (j > 1):
        if (j < a.shape[1] - 1):
            if a[i, j+unit]:
                print "only now I do stuff!"

并尝试了这个(看起来因为没有按预期工作而变得简单):

if (not gotside) and (j > 1) and (j < a.shape[1] - 1) and a[i, j+unit]:
    print "I'm well tested but not so indented..."

然后我尝试使用“或”而不是“和”,但没有奏效,因为(后来我发现)当你使用 x and y 甚至 x or y 时,你会得到 x, y 之一,而不是一个True, False,根据文档。

所以,我不知道如何将几个测试一个接一个地进行(最好在同一行中,使用布尔运算符),以使整个表达式在第一个测试评估后立即返回 False为假。

感谢阅读!

【问题讨论】:

  • 您指的是短路。是的,我相信在您的简化示例中,如果 gotside 是真的,它应该“短路”等式,因此不要打扰其余的。如果不是,那么您可能需要用括号将所有其余的检查括在一组括号中。
  • 即使布尔表达式可能不返回布尔值,但在布尔上下文中计算结果时,它会按照您的预期进行解释。

标签: python boolean short-circuiting truthtable


【解决方案1】:

你的例子应该有效。

if x and y and z:
    ...

仅当 x、y 和 z 均未计算为 False 时才会发生,并且在 Python 中,and 短路,因此一旦一项失败,将返回 False 值。我们可以很容易地证明这一点:

>>> def test(n):
...     print("test", n)
...     return n
... 
>>> test(1) and test(2)
test 1
test 2
2
>>> test(0) and test(2)
test 0
0
>>> test(0) and test(2) and test(3)
test 0
0
>>> test(1) and test(0) and test(3)
test 1
test 0
0

【讨论】:

  • 非常有趣的表达方式。我认为没有什么好争论的了 :o) 非常感谢!
【解决方案2】:

我明白你的担忧,但请记住,只要 Python 中的 if 语句中有某些内容,它就会隐式转换为 bool 用于条件。因此,虽然3 or 2 返回33 and 2 在独立完成时返回2,但说if 3 or 2 实际上相当于说if bool(3 or 2),所以你会得到逻辑返回的假值或真值在条件中使用时,无论布尔逻辑在其他上下文中返回什么。

【讨论】:

    【解决方案3】:

    是的,我必须同意其他人的说法,即您的示例应该按您的意愿工作。 x or y 返回 x、y 之一是对的,但该对象将能够被评估为 True 或 False。这就是 python 评估 if 语句的方式。它应该像所写的那样工作,因为您的表达式将按顺序进行评估,并且一旦该行中的任何测试返回为 False(或 0,或 []{} 等),它将返回 False。如果 python 实际尝试过会引发错误的测试,您可以看到这一点。

    x = 1; y = 2
    if x < y and x == y and d['a']: # d doesn't exist
        print 'This will never be printed'
    

    如果您的代码没有按预期运行,请详细说明您期望它做什么以及它实际在做什么。

    【讨论】:

    • +1 是一个很好的例子,表明短路后的代码甚至从未被评估过(因为如果是这样会引发异常)。
    • 很好的例子。实际上我的代码正在评估正确(由于其他错误而无法正常工作)。有趣的是,不存在的对象被评估为 False 而不是引发错误。谢谢,+1!
    • @heltonbiker 这不太对;如果访问了不存在的东西,它将返回错误,而不是 False。在我的代码中 d['a'] 不会引发错误,因为它从未被评估过。 Python一到达x == y就停止,因为那是False,这意味着我的整个ands链是False。它不会费心检查最后一个术语,因为它没有必要。如果是这样,则会引发错误。这就是人们谈论“短路”功能时的意思。
    【解决方案4】:

    我对您未包含的代码做了一些假设,并添加了它以使程序运行:

    gotside = False
    j = 2
    i = 1
    unit = 3
    
    class A:
        def __init__(self):
            self.shape = [1, 4]
        def __getitem__(self, pos):
            return pos
    
    a = A()
    
    
    if (not gotside):
        if (j > 1):
            if (j < a.shape[1] - 1):
                if a[i, j+unit]:
                    print("only now I do stuff!")
    
    if (not gotside) and (j > 1) and (j < a.shape[1] - 1) and a[i, j+unit]:
       print("I'm well tested but not so indented...")
    

    对我来说,这适用于 python 2.5、2.6、2.7 和 3.2:

    only now I do stuff!
    I'm well tested but not so indented...
    

    如果这对你有用,你能检查一下上面的程序吗?如果是这样,您能否提供有关您使用的类的更多信息 - 特别是变量a 的类。

    【讨论】:

    • 非常感谢您的代码。实际上提到的代码是有效的,在我的程序的其他地方还有其他断言失败。无论如何,我认为这些答案,包括你在内,将来可能会帮助有类似疑问的人。再次感谢。 +1
    【解决方案5】:

    Python(以及大多数其他编程语言)中的布尔值和运算符提供“短路”功能。这意味着,如果第一项或表达式的计算结果为 false,则甚至不计算第二项:

    >>> False and expensiveFunctionReturningBool()
    False
    

    永远不会调用昂贵的函数,因为 Python 解释器在第一项被确定为 False 后立即将表达式评估为 False。这是可行的,因为在布尔逻辑中,如果 and 表达式的一侧为假,则整个表达式根据定义为假

    Python 还为 or 使用短路逻辑。在这种情况下,如果第一项被确定为 True,则永远不会评估第二项。

    >>> True or expensive()
    True
    

    因此,布尔表达式可用于折叠嵌套的 if 语句(前提是它们一个接一个地立即声明),如果通过牢记短路逻辑巧妙地使用它们,它们还可以优化条件表达式。

    祝你好运!

    【讨论】:

    • 我想你的意思是True or expensive()。我试图编辑,但它不允许我,因为编辑是
    • 我添加了“只要它们一个接一个地立即声明”。提出的策略非常好。
    • 谢谢,@heltonbiker 和 Joel Cornett。不敢相信我在谈到 or.... =] 后立即写了“and”
    猜你喜欢
    • 2021-04-26
    • 2020-10-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-16
    • 1970-01-01
    • 2012-05-15
    相关资源
    最近更新 更多