[英]Python: Lazy Function Evaluation in any() / all()
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
只是short-circuit ,而不是lazy ,這就是這里的區別。
any
正在接受一個 iterable 。 因此,應該有一種創建迭代器的方法,它不會預先評估其元素,而是將它們未評估的傳遞給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'))]
)
這樣,只要生成器中的一個函數調用計算為True
, any
就會停止調用生成器中的next()
元素,這意味着函數計算是完全惰性的。
wjandrea在評論中提到了另一種推遲函數計算的巧妙方法:我們也可以使用lambda 表達式,如下所示:
>>> any(f() for f in [lambda: func('s'), lambda: func('t')]
's'
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.