2016-07-22 70 views
7

我有一個算法,可以生成素清單作爲發電機:蟒蛇過濾器不工作

def _odd_iter(): 
    n=3 
    while True: 
     yield n 
     n=n+2 

def _not_divisible(n): 
    return lambda x: x % n > 0 

def primes(): 
    yield 2 
    L=_odd_iter() 
    while True: 
     n=next(L) 
     yield n 
     L=filter(_not_divisible(n), L) 

x=1 
for t in primes(): 
    print(t) 
    x=x+1 
    if x==10: 
     break 

但是如果我把lambda函數爲filter功能直接,如下圖所示:

def primes(): 
    yield 2 
    L=_odd_iter() 
    while True: 
     n=next(L) 
     yield n 
     L=filter(lambda x: x%n>0, L) 

我只能得到一個奇怪的列表,而不是主要列表。看來filter功能不起作用。

我該怎麼辦?

+2

您是否嘗試將其更改爲'lambda x = x:...'? – TigerhawkT3

+1

這真是太奇怪了。 –

+0

該算法的第一個版本根本不適用於我。以下代碼:'_ = primes();下一頁打印(_);下一頁打印(_);然後打印(_);'打印'2',然後'3',然後掛起。你使用的是什麼版本的Python? –

回答

6

這是一個簡單的程序,它說明了同樣的問題。

adders = [] 
for i in range(4): 
    adders.append(lambda a: i + a) 
print(adders[0](3)) 

儘管人們所期望的輸出是3,實際輸出爲6。 這是因爲Python中的閉包在創建lambda時會記住變量的名稱和範圍,而不是它的值。由於在使用lambda時i已被修改,所以lambda使用最新值i

同樣的事情發生在你的函數中。每當修改n時,各種過濾器中的所有lambda函數也會被修改。因此,迭代器到達9時,所有濾波器都是過濾因子7,而不是53

因爲在第一種方法中,每次調用_not_divisible時都會創建一個新範圍,該功能按預期工作。

如果你絕對必須直接使用lambda,你可以使用第二個參數是這樣的:

def primes(): 
    yield 2 
    L=_odd_iter() 
    while True: 
     n=next(L) 
     yield n 
     L=filter(lambda x, n=n: x%n>0, L) 
+1

謝謝@merlyn,你給出了很好的答案 –

4

的作品是lambda x, n=n: x%n != 0拉姆達。如果你想在定義lambda時捕獲n,你顯然需要這樣做。否則,lambda只能在計算lambda時查找變量名。在你的情況下,我認爲這意味着在稍後的while循環中鎖定n值。

+0

有什麼區別方式閉包在Python 2和Python 3中工作? –

+1

@ juanpa.arrivillaga沒有區別......但是這段代碼依賴於python 3,因爲在python 3中'filter'返回一個生成器而不是一個計算值。 – donkopotamus

+0

@donkopotamus OH當然!您應該將其作爲答案發布。 –