2017-09-04 35 views
4

我試圖創建一個函數列表,然後應用於數字列表。我通過遍歷一系列數字來完成此操作,並使用for循環中的每個數字定義一個lambda函數。然後第二個for循環用於將每個函數應用於10個數字的相同列表。在另一個列表中應用lambda函數列表時發生意外的行爲

問題是我的lambdas列表似乎都採用for循環的最終值。

fx_lst = [] 
for k in range(1,3,1): 
    func = lambda x_: k * x_ 
    fx_lst.append(func) 
xlst = range(1,10,1) 

for fx in fx_lst: 
    ylst = map(lambda xin_: fx(xin_), xlst) 
    print i, ylst 

ylst打印: [2,4,6 ... 18] [2,4,6 ... 18]

很顯然,我不明白一些事情的方式lambda表達式店可變信息。

回答

3

發生了什麼事是你的lambda表達式被綁定到循環變量k而不是與之相關的價值,就是這樣。即使在循環之後,循環變量k仍然存在,因此這些lambda可以訪問它。

的一種可能的解決方案,我知道是lambda鑽營:

In [129]: fx_lst = [] 
    ...: for k in range(1,3,1): 
    ...:  func = (lambda k=k: lambda x_: k * x_)(k) 
    ...:  fx_lst.append(func) 
    ...:  

In [130]: fx_lst[0](3) 
Out[130]: 3 

In [131]: fx_lst[1](3) 
Out[131]: 6 

功能(lambda k=k: lambda x_: k * x_)(k)基本上是一個高階函數,通過固定參數恆定的一個減少的函數採取兩個參數來採取一個,功能提前。範圍固定爲k=k,因此外部循環變量不會與lambda範圍衝突。

對於你的榜樣,我得到

[1, 2, 3, 4, 5, 6, 7, 8, 9] 
[2, 4, 6, 8, 10, 12, 14, 16, 18] 

其他解決方法包括使用functools.partial代替,它不完全一樣的事情。

+1

很好解釋,並完美的作品。謝謝。我以前從來沒有聽說過捲餅,所以這是我需要研究的東西! – user2185097

+2

@ user2185097很高興能幫到您!您可能會對https://stackoverflow.com/questions/36314/what-is-currying感興趣 –

1

我以前碰到這個問題,以下是一個解決方案:

def apply_filters(filters, iterator): 
    from functools import reduce 
    return list(reduce(lambda s, f: filter(f, s), filters, iterator)) 

用法:

my_filters = [lambda x: x % 2 == 0, lambda x: x % 5 == 0] 
result = apply_filters(my_filters, range(1, 100)) 
print(result) 
# [10, 20, 30, 40, 50, 60, 70, 80, 90] 
+0

你能解釋它爲什麼會發生? – user2185097

+0

神奇的部分是reduce,它將一個過濾器應用到迭代器並獲得一個子序列,然後對該子序列應用另一個過濾器。 –

相關問題