問題:下面這段代碼的輸出結果將是什麼?
def multipliers():
return [lambda x: i * x for i in range(4)]
print([m(2) for m in multipliers()])
答:上面代碼輸出的結果是 [6, 6, 6, 6](不是我們想的 [0, 2, 4, 6])。
上述問題產生的原因是 Python 閉包的延遲綁定。這意味着內部函數被調用時,參數的值在閉包內進行查找。因此,當任何由 multipliers()返回的函數被調用時,i 的值將在附近的範圍進行查找。那時,不管返回的函數是否被調用,for 循環已經完成,i 被賦予了最終的值 3。因此,每次返回的函數乘以傳遞過來的值 3,因爲上段代碼傳過來的值是 2,它們最終返回的都是 6 即 (3*2)。
問題:什麼是閉包?
在函數內部再定義一個函數,並且這個函數用到了外邊函數的變量,那麼將這個函數以及用到的一些變量稱之爲 閉包。
問題:如何修改上面的 multipliers 的定義從而產生想要的結果?
一種解決方法就是用 Python 生成器。
def multipliers_1():
for i in range(4):
yield lambda x: i * x
print([m(2) for m in multipliers_1()])
另外一個解決方案就是創造一個閉包,利用默認參數立即綁定。
def multipliers_2():
return [lambda x, i=i: i * x for i in range(4)]
print([m(2) for m in multipliers_2()])