2016-12-06 52 views
3

我寫了這個簡單的代碼:與lambda函數Python中封閉的範圍變量

def makelist(): 
    L = [] 
    for i in range(5): 
    L.append(lambda x: i**x) 
    return L 

OK,現在我打電話

mylist = makelist() 

,因爲封閉的範圍變量擡起頭來時,嵌套函數是後來被稱爲,它們都有效記得相同的值: 正因爲如此,我希望能夠找到循環變量對最後的循環迭代的價值,但是當我檢查我的列表我看到:

>>> mylist[0](0) 
1 
>>> mylist[0](1) 
4 
>>> mylist[0](2) 
16 
>>> 

我很困惑,爲什麼我的代碼不保留最後的for循環值?爲什麼我沒有明確地保留封閉的範圍值與默認參數是這樣的:提前

回答

3

即使i隨着時間的推移取得多個值,但實際上只有一個變量,i。循環過程中正在更改i的內容。但封閉捕捉變量,而不是值。在你調用lambda之前,沒有任何內容會被評估。當您調用該函數時,您可以訪問當前值i,該值恰好是最後一個值。

至於爲什麼i=i解決了這個問題,這是例如在The Hitchhiker's guide to Python常見的問題)解釋說:

Python的默認參數進行評估,一旦當函數的定義,而不是每次函數稱爲(就像在說,Ruby)。這意味着如果您使用可變默認參數並對其進行變異,那麼您將會爲該函數的所有將來調用改變該對象。

因此,您所創建的瓶蓋內發生的每個新的綁定(並碰巧被命名爲i就像外面的那個)創建時關閉有它的默認值被計算。因此,您有適當的「正確」價值,隨時可以在關閉時被使用。

3

首先

L.append(lambda x, i=i: i ** x) 

謝謝,觀察列表中的所有5個功能是相同的,因爲它們都使用最終i從內側makelist值。

i雖然是在評估lambda表達式時創建的關閉的一部分。這意味着,如果你在範圍內指定一個新值i,你電話makelist的功能,這並不影響任何功能。他們從作爲關閉結果而不是全局作用域的函數附加的命名空間中查找i的值。