Python3.8 `all()` not short circuiting



好吧,我可能只是有一个糟糕的工作日,但据我所知all()应该短路根据文件。

all()应等价于:

def all(iterable):
for element in iterable:
if not element:
return False
return True

也相当于菊花链and

所以下面的代码应该做同样的事情:

all((True, print('This should print and stop'), print("this shouldn't print")))
True and print('This should print and stop') and print("this shouldn't print")

然而最上面的一个会同时打印(即完全评估每个部分)但是底部短路了

这是Python(3.8.2)的错误还是我突然没有得到这个正确的?

Repl with example: https://repl.it/join/scxbpnhc-syntactical01

all内部的迭代短路,但是每次调用print都必须进行评估,以便在调用all之前创建作为参数传递的tuple

如果没有def语句,在Python中没有简单的方法来创建任意的惰性序列。你可以写
def foo():
yield True
yield print("This should print and stop")
yield print("this shouldn't print")
all(foo())

但是没有等价的纯表达式。您需要遍历一些来使用生成器表达式,例如

(x(y) for x, y in zip([id, print, print], 
[True, 
"This should print and stop",
"this shouldn't print"]))

会如你所愿。

>>> all(x(y) for x, y in zip([id, print, print], [True, "This should print and stop", "this shouldn't print"]))
This should print and stop
False

现在,printall内部调用,而不是作为传递给all的实参求值的一部分。

Python的all接受一个可迭代对象作为参数

在你的问题中的例子的构造过程中,在这种情况下是一个元组,元组字面中的函数被调用,返回值插入到元组字面中;与:

>>> tup=(True, print('this'), False, print('not this'))
this
not this

如果你想要一个动态的集合形式你可以这样做:

def example_func(*args):
return args
g2all=(True, (print, 'this', 'and this'), False, (print, 'not this'), (example_func,1,2,3,4))

这依赖于这样一个事实,即您可以通过名称引用函数,如果没有()调用操作符,则该函数尚未被调用:

>>> g2all
(True, (<built-in function print>, 'this', 'and this'), False, (<built-in function print>, 'not this'), (<function example_func at 0x10d0a9430>, 1, 2, 3, 4))

您可以在all中使用生成器:

>>> all(f[0](*tuple(f[1:])) if isinstance(f, tuple) and callable(f[0]) else f for f in g2all)
this and this
False
all

发现一个false值时,和函数的调用停止。

最新更新