簡體   English   中英

Python:any() / all() 中的惰性函數求值

[英]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'))]
)

這樣,只要生成器中的一個函數調用計算為Trueany就會停止調用生成器中的next()元素,這意味着函數計算是完全惰性的。

wjandrea在評論中提到了另一種推遲函數計算的巧妙方法:我們也可以使用lambda 表達式,如下所示:

>>> any(f() for f in [lambda: func('s'), lambda: func('t')]
's'

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM