亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

(lambda)函數閉包捕獲了什么?

(lambda)函數閉包捕獲了什么?

最近我開始玩Python,我遇到了一些特殊的閉包方式。請考慮以下代碼:adders=[0,1,2,3]for i in [0,1,2,3]:    adders[i]=lambda a: i+aprint adders[1](3)它構建了一個簡單的函數數組,它接受單個輸入并返回由數字添加的輸入。函數在for循環中構造,迭代器i從中循環0到3。對于這些數字中的每一個,lambda都會創建一個函數i,該函數捕獲并將其添加到函數的輸入中。最后一行將第二個lambda函數3作為參數調用。令我驚訝的是輸出結果是6。我期待一個4。我的理由是:在Python中,一切都是一個對象,因此每個變量都是指向它的指針。在創建lambda閉包時i,我希望它存儲一個指向當前指向的整數對象的指針i。這意味著當i分配一個新的整數對象時,它不應該影響先前創建的閉包。遺憾的是,adders在調試器中檢查數組表明它確實存在。所有的lambda功能指的最后一個值i,3,這將導致adders[1](3)返回6。這讓我想知道以下內容:閉包捕獲的內容是什么?什么是最優雅的方式來說服lambda函數以更改其值i時不會受到影響的方式捕獲當前i值?
查看完整描述

4 回答

?
慕后森

TA貢獻1802條經驗 獲得超5個贊

您可以使用具有默認值的參數強制捕獲變量:


>>> for i in [0,1,2,3]:

...    adders[i]=lambda a,i=i: i+a  # note the dummy parameter with a default value

...

>>> print( adders[1](3) )

4

我們的想法是聲明一個參數(巧妙地命名i)并給它一個你想要捕獲的變量的默認值(值  i)


查看完整回答
反對 回復 2019-05-27
?
慕斯王

TA貢獻1864條經驗 獲得超2個贊

為了完整性,您對第二個問題的另一個答案是:您可以在functools模塊中使用partial。

通過從運營商導入add,Chris Lutz提出的示例變為:

from functools import partialfrom operator import add   # add(a, b) -- Same as a + b.adders = [0,1,2,3]for i in [0,1,2,3]:
   # store callable object with first argument given as (current) i
   adders[i] = partial(add, i) print adders[1](3)


查看完整回答
反對 回復 2019-05-27
?
qq_笑_17

TA貢獻1818條經驗 獲得超7個贊

請考慮以下代碼:

x = "foo"def print_x():
    print x

x = "bar"print_x() # Outputs "bar"

我想大多數人都不會發現這種混亂。這是預期的行為。

那么,為什么人們認為它在循環中完成時會有所不同?我知道我自己犯了這個錯誤,但我不知道為什么。這是循環?或者也許是lambda?

畢竟,循環只是一個較短的版本:

adders= [0,1,2,3]i = 0adders[i] = lambda a: i+a
i = 1adders[i] = lambda a: i+a
i = 2adders[i] = lambda a: i+a
i = 3adders[i] = lambda a: i+a


查看完整回答
反對 回復 2019-05-27
?
慕運維8079593

TA貢獻1876條經驗 獲得超5個贊

你的第二個問題已得到解答,但至于你的第一個問題:

封閉捕獲到底是什么?

Python中的范圍是動態的和詞匯的。閉包將始終記住變量的名稱和范圍,而不是它指向的對象。由于示例中的所有函數都在同一作用域中創建并使用相同的變量名,因此它們始終引用相同的變量。

編輯:關于如何克服這個問題的另一個問題,有兩種方法可以想到:

  1. 最簡潔但不嚴格等同的方式是Adrien Plisson推薦的方式。使用額外參數創建lambda,并將額外參數的默認值設置為要保留的對象。

  2. 每次創建lambda時,創建一個新范圍會更冗長但更少hacky:

    >>> adders = [0,1,2,3]>>> for i in [0,1,2,3]:...     adders[i] = (lambda b: lambda a: b + a)(i)...     >>> adders[1](3)4>>> adders[2](3)5

    這里的范圍是使用一個新函數(lambda,為簡潔起見)創建的,它綁定了它的參數,并傳遞你想要綁定的值作為參數。但是,在實際代碼中,您很可能會使用普通函數而不是lambda來創建新范圍:

    def createAdder(x):
        return lambda y: y + x
    adders = [createAdder(i) for i in range(4)]


查看完整回答
反對 回復 2019-05-27
  • 4 回答
  • 0 關注
  • 1361 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號