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

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

python 3 lambda 的參數綁定似乎已損壞

python 3 lambda 的參數綁定似乎已損壞

慕娘9325324 2023-07-18 14:59:56
我在 CentOS 7 環境中使用 Python 3.6.10。我正在嘗試創建一個基于結構化規范執行的命令列表。將其視為 lambda 列表似乎很自然且符合 Python 風格。我通過遍歷規范來構建 lambda 列表。令我驚訝的是,當我執行結果時,我發現每個 lambda 都是相同的,因為它在創建 lambda 時沒有捕獲其參數。我認為這是一個錯誤。以下是說明該行為的示例代碼:specification = {    'labelOne': ['labelOne.one', 'labelOne.two', 'labelOne.three', 'labelOne.four', 'labelOne.five'],    'labelTwo': ['labelTwo.one', 'labelTwo.two', 'labelTwo.three', 'labelTwo.four', 'labelTwo.five'],    'labelThree': ['labelThree.one', 'labelThree.two', 'labelThree.three', 'labelThree.four', 'labelThree.five'],    'labelFour': ['labelFour.one', 'labelFour.two', 'labelFour.three', 'labelFour.four', 'labelFour.five'],    'labelFive': ['labelFive.one', 'labelFive.two', 'labelFive.three', 'labelFive.four', 'labelFive.five'],    }lambdas = []for label, labelStrings in specification.items():    for labelString in labelStrings:        lambdaString = f"""Label: \"{label}\" with labelString: \"{labelString}\""""        oneArgLambda = lambda someArg: print(someArg, lambdaString)        lambdas.append(oneArgLambda)for each in lambdas:    each('Show: ')我期望看到這個:Show:  Label: "labelOne" with labelString: "labelOne.one"Show:  Label: "labelOne" with labelString: "labelOne.two"Show:  Label: "labelOne" with labelString: "labelOne.three"Show:  Label: "labelOne" with labelString: "labelOne.four"Show:  Label: "labelOne" with labelString: "labelOne.five"Show:  Label: "labelTwo" with labelString: "labelTwo.one"Show:  Label: "labelTwo" with labelString: "labelTwo.two"Show:  Label: "labelTwo" with labelString: "labelTwo.three"Show:  Label: "labelTwo" with labelString: "labelTwo.four"lambda 的參數綁定是在執行 lambda 時發生的,而不是在創建 lambda 時發生的。這至少是出乎意料的,而且我認為可以說是錯誤的。我認為 lambda 盡管有局限性,但應該創建一個 CLOSURE —— 它的整個目的是捕獲其參數在創建時的狀態,以便稍后在計算 lambda 時可以使用它們。這就是為什么它被稱為“閉包”,因為它在創建時關閉了其參數的值。我有什么誤解嗎?
查看完整描述

3 回答

?
德瑪西亞99

TA貢獻1770條經驗 獲得超3個贊

正如您所說,它創建了 CLOSURE,并且閉包在lambdaString的上部范圍中使用指定變量,但技巧是所有 lambda 都使用對lambdaString的相同引用,并且因為每次它記住最后一個時都更改它。例如:


c = ['one', 'two']

res = []


for i in range(2):

    for y in c:

        def la(x):

            print(x, y)

        res.append(la)


for la in res:

    la('Show: ')

# Show:  two

# Show:  two

# Show:  two

# Show:  two

你只需要另一個關閉來防止這種情況


c = ['one', 'two']

res = []


for i in range(2):

    for y in c:

        def closure_y(y):

            def la(x):

                print(x, y)

            return la

            

        res.append(closure_y(y))


for la in res:

    la('Show: ')

# Show:  one

# Show:  two

# Show:  one 

# Show:  two

完整代碼可能是


specification = {

    'labelOne': ['labelOne.one', 'labelOne.two', 'labelOne.three', 'labelOne.four', 'labelOne.five'],

    'labelTwo': ['labelTwo.one', 'labelTwo.two', 'labelTwo.three', 'labelTwo.four', 'labelTwo.five'],

    'labelThree': ['labelThree.one', 'labelThree.two', 'labelThree.three', 'labelThree.four', 'labelThree.five'],

    'labelFour': ['labelFour.one', 'labelFour.two', 'labelFour.three', 'labelFour.four', 'labelFour.five'],

    'labelFive': ['labelFive.one', 'labelFive.two', 'labelFive.three', 'labelFive.four', 'labelFive.five'],

    }


lambdas = []

for label, labelStrings in specification.items():

    for labelString in labelStrings:

        lambdaString = f"""Label: \"{label}\" with labelString: \"{labelString}\""""


        def clousure(lambdaString):

            oneArgLambda = lambda someArg: print(someArg, lambdaString)

            return oneArgLambda


        lambdas.append(clousure(lambdaString))


for each in lambdas:

    each('Show: ')


查看完整回答
反對 回復 2023-07-18
?
婷婷同學_

TA貢獻1844條經驗 獲得超8個贊

您還有一些其他評論和答案來解釋正在發生的事情,并且您的問題“有趣”是因為它迫使讀者對代碼和各種綁定問題感到困惑。


但是,如果我在審查過程中從同事那里看到了您的代碼,我會要求重寫 - 不是因為我會立即知道存在錯誤,而是因為它需要太多的頭腦來思考是否來自周圍的綁定(并改變) 范圍將完全按照希望的方式運行。


相反,堅持在你的程序中實行更嚴格的紀律,從而減輕你的讀者(大多數時候誰是你)的認知負擔。具體來說,將函數創建移至真正隔離的范圍,并將所有不同的輸入傳遞給該函數創建者。這種方法是可靠的,因為它要么在第一次嘗試時起作用,要么完全失?。ㄈ绻雎詫⑺行枰膮祩鬟f給函數創建者)。


一種方法是:


# A function to create another function, with non-surprising argument binding.

# We expect nothing from the surrounding scope. All business can be done locally.

def get_func(label, x):

    return lambda prefix: print(f'''{prefix} => {label}: {x}''')


# Some input data.

specification = {

    label : [label + str(n) for n in range(3)]

    for label in ('A', 'B', 'C')

}


# Use that data to create some functions.

funcs = [

    get_func(label, x)

    for label, xs in specification.items()

    for x in xs

]


# Run 'em.

for f in funcs:

    f('Show')


查看完整回答
反對 回復 2023-07-18
?
幕布斯7119047

TA貢獻1794條經驗 獲得超8個贊

這是一個替代方案


lambdas = []

for label, labelStrings in specification.items():

    for labelString in labelStrings:

        lambdaString = f"""Label: \"{label}\" with labelString: \"{labelString}\""""

        oneArgLambda = lambda someArg, lambdaString: print(someArg, lambdaString)

        lambdas.append((oneArgLambda, lambdaString))


for f, lambdaString in lambdas:

    f('Show: ', lambdaString)


查看完整回答
反對 回復 2023-07-18
  • 3 回答
  • 0 關注
  • 155 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

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

幫助反饋 APP下載

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

公眾號

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