Python 中的逻辑运算符是惰性的。具有以下定义:
def func(s):
print(s)
return True
呼叫
or
接线员
>>> func('s') or func('t')
's'
仅评估第一个函数调用,因为
or
认识到表达式的计算结果为
True
,无论第二个函数调用的返回值是什么。 and
确实有类似的行为。
但是,当按以下方式使用
any()
(类似:all()
)时:
>>> any([func('s'), func('t')])
's'
't'
所有函数调用都会被评估,因为内部列表是在
any
开始迭代其项目的布尔值之前首先构建的。当我们省略列表构造并只写时,也会发生同样的情况
>>> any(func('s'), func('t'))
's'
't'
这样我们就失去了
any
作为短路的力量,这意味着一旦可迭代的第一个元素为真,它就会中断。如果函数调用的成本很高,那么预先评估所有函数就会造成很大的损失,并且浪费了any
的这种能力。从某种意义上说,人们可以将其称为 Python 陷阱,因为对于尝试利用 any
的此功能的用户来说可能会出乎意料,而且因为 any
通常被认为是链接一系列 or
的另一种语法方式。
陈述。但any
只是短路,而不是懒惰,这就是这里的区别。
any
正在接受一个可迭代的。因此,应该有一种方法来创建一个迭代器,它不会预先评估其元素,而是将未评估的元素传递给 any
并让它们仅在 any
内部评估,以实现完全惰性评估。
所以,问题是:我们如何使用
any
进行真正的惰性函数求值?这意味着:我们如何制作一个 any
可以使用的函数调用迭代器,而不提前评估所有函数调用?
我们可以使用生成器表达式,分别传递函数及其参数,并仅在生成器中进行计算,如下所示:
>>> any(func(arg) for arg in ('s', 't'))
's'
对于具有不同签名的不同函数,可能如下所示:
any(
f(*args)
for f, args in [(func1, ('s',)), (func2, (1, 't'))]
)
这样,一旦生成器中的一个函数调用计算结果为
any
,next()
将停止调用生成器中的 True
元素,这意味着函数计算是完全惰性的。
wjandrea在评论中提到了另一种推迟函数求值的巧妙方法:我们还可以使用lambda表达式,如下所示:
>>> any(
>>> f()
>>> for f in [
>>> lambda: func('s'),
>>> lambda: func('t'),
>>> ]
>>>)
's'
令人遗憾的是,any() 和 all() 没有逻辑功能,并且受到这种有点人为的约束的限制。相反,一次循环构造可以很方便,这也与早期返回的函数有关。
once-thru 循环可以是处理它的便捷方法,特别是在需要生成然后使用中间结果的情况下。
for _ in range(1):
val = func1()
if not val:
break
val = intermediate_func1()
if not func3(val):
break
val2 = intermediate_func2(val)
if not func4(val2):
break
result = the_really_expensive_function(val, val2)
if result:
return True, result
return False, None
使用函数和提前返回的类似构造。
def example():
val = func1()
if not val:
return False, None
val1 = intermediate_func1(val)
if not func3(val1):
return False, None
val2 = intermediate_func2(val1)
if not func4(val2):
return False, None
result = the_really_expensive_function(val, val2)
if result:
return True, result
return False, None
我想使用什么(但不能;这仅适用于 := 运算符):
if all(
val := func1(),
func3(val1 := intermediate_func1(val)),
func4(val2 := intermediate_func2(val)),
result := the_really_expensive_function(val, val2),
):
return result, True
return False, None
也许未来这是可行的。
--雷