Python 的
any
和 all
内置函数 应该短路,就像逻辑运算符 or
和 and
一样。
但是,假设我们有一个像这样的函数定义:
def func(s):
print(s)
return True
并使用它构建传递给
any
或 all
: 的值列表
>>> any([func('s'), func('t')])
's'
't'
True
由于必须在调用
any
之前构造列表,因此该函数也会提前评估,有效防止短路。
如果函数调用的成本很高,那么预先评估所有函数就会造成很大的损失,并且浪费了
any
的这种能力。
any
接受任何类型的iterable,我们如何推迟func
的求值,从而使any
的短路阻止func(t)
的调用?
我们可以使用生成器表达式,分别传递函数及其参数,并仅在生成器中进行计算,如下所示:
>>> any(func(arg) for arg in ('s', 't'))
's'
True
对于具有不同签名的不同函数,可能如下所示:
any(
f(*args)
for f, args in [(func1, ('s',)), (func2, (1, 't'))]
)
这样,一旦一个函数调用计算结果为
any
,True
将停止迭代生成器,这意味着函数计算是完全惰性的。
推迟函数求值的另一种巧妙方法是使用 lambda 表达式,如下所示:
>>> any(
... f()
... for f in [lambda: func('s'), lambda: func('t')]
... )
's'
True
令人遗憾的是
any()
和all()
没有逻辑功能并且受到这种有点人为的约束的限制。相反,一次性循环构造可能很方便,特别是在需要生成和使用中间结果的情况下。这也与提前返回的函数有关。
def example():
for _ in range(1):
val = func1()
if not val:
break
val1 = intermediate_func1(val)
if not func3(val1):
break
val2 = intermediate_func2(val1)
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(val1)),
result := the_really_expensive_function(val, val2),
):
return True, result
return False, None
也许未来这是可行的。