Any/All python 短路:为什么以下不起作用?

Any/All python short-circuit: Why doesn't the following work?

基于我在其他 Whosebug 页面上看到的内容:

以下代码应该短路:

any(True, 2+2, False, 2/0)
all(True, 2+2, False, 2/0)
any([True, 2+2, False, 2/0])
all([True, 2+2, False, 2/0])

但对于他们中的每一个,我都会得到一个 ZeroDivisionError: division by zero

我错过了什么吗?为什么会报错?

是的,短路发生在python

In [23]: False and 3/0
Out[23]: False

In [24]: True and 3/0
---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
<ipython-input-24-a08823d6496a> in <module>
----> 1 True and 3/0

ZeroDivisionError: division by zero

使用dis模块,

In [32]: dis.dis("all([True, 2+2, False, 2/0])")
  1           0 LOAD_NAME                0 (all)
              2 LOAD_CONST               0 (True)
              4 LOAD_CONST               1 (4)
              6 LOAD_CONST               2 (False)
              8 LOAD_CONST               3 (2)
             10 LOAD_CONST               4 (0)
             12 BINARY_TRUE_DIVIDE
             14 BUILD_LIST               4
             16 CALL_FUNCTION            1
             18 RETURN_VALUE

In [33]: dis.dis("any(True, 2+2, False, 2/0)")
  1           0 LOAD_NAME                0 (any)
              2 LOAD_CONST               0 (True)
              4 LOAD_CONST               1 (4)
              6 LOAD_CONST               2 (False)
              8 LOAD_CONST               3 (2)
             10 LOAD_CONST               4 (0)
             12 BINARY_TRUE_DIVIDE
             14 CALL_FUNCTION            4
             16 RETURN_VALUE

当您查看函数调用时,BINARY_TRUE_DIVIDEanyall 之前计算,因为表达式在任何函数调用之前先计算

您的代码错误,因为必须在将表达式传递给函数之前对其求值。

在这种情况下,短路实际上意味着一旦他们找到不同的值,他们就会 return 而不会检查剩余的值。这与 andor 做的短路不同,后者实际上可以避免计算表达式。

为了说明,让我们使用一个迭代器,它将被消耗:

>>> a = iter([1, 0, 2, 3])
>>> all(a)  # Search until a falsy value
False
>>> list(a)  # Show what's left in the iterator
[2, 3]

你可以看到它在 0 上消耗了 10,returning 因为它是假的。


现在,如果您确实想使用 anyall 进行惰性求值,您可以在生成器表达式中调用 lambda:

>>> any(e() for e in [lambda: 1, lambda: 0, lambda: 2/0])
True
>>> all(e() for e in [lambda: 1, lambda: 0, lambda: 2/0])
False

(感谢 对这一点的启发。)