Any/All python 短路:为什么以下不起作用?
Any/All python short-circuit: Why doesn't the following work?
基于我在其他 Whosebug 页面上看到的内容:
- Does all(list) use short circuit evaluation?
- Is the shortcircuit behaviour of Python's any/all explicit?
以下代码应该短路:
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_DIVIDE
在 any
或 all
之前计算,因为表达式在任何函数调用之前先计算
您的代码错误,因为必须在将表达式传递给函数之前对其求值。
在这种情况下,短路实际上意味着一旦他们找到不同的值,他们就会 return 而不会检查剩余的值。这与 and
和 or
做的短路不同,后者实际上可以避免计算表达式。
为了说明,让我们使用一个迭代器,它将被消耗:
>>> 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
上消耗了 1
和 0
,returning 因为它是假的。
现在,如果您确实想使用 any
和 all
进行惰性求值,您可以在生成器表达式中调用 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
(感谢 对这一点的启发。)
基于我在其他 Whosebug 页面上看到的内容:
- Does all(list) use short circuit evaluation?
- Is the shortcircuit behaviour of Python's any/all explicit?
以下代码应该短路:
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_DIVIDE
在 any
或 all
之前计算,因为表达式在任何函数调用之前先计算
您的代码错误,因为必须在将表达式传递给函数之前对其求值。
在这种情况下,短路实际上意味着一旦他们找到不同的值,他们就会 return 而不会检查剩余的值。这与 and
和 or
做的短路不同,后者实际上可以避免计算表达式。
为了说明,让我们使用一个迭代器,它将被消耗:
>>> 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
上消耗了 1
和 0
,returning 因为它是假的。
现在,如果您确实想使用 any
和 all
进行惰性求值,您可以在生成器表达式中调用 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
(感谢