匿名函數在列表生成式中的應用產生的閉包函數延遲綁定問題


匿名函數在列表生成式 (推導式) 中的應用產生的閉包函數延遲綁定問題

先看下面這個函數:

def num():
    return [lambda x: x * i for i in range(4)]

print([func(2) for func in num()])

再不運行結果的情況下心算下它的結果......是不是算到 [0,2,4,6] ?

於是在pycharm里面運行了一下 : [6,6,6,6], 百思不得其解, 我們先來把匿名函數變成普通函數, 這樣好理解一點 :

def num():
    sub=[]
    for i in range(4):
        def bar(x):
            return i*x
        sub.append(bar)
    return sub

print([func(2) for func in num()])

我們可以看到它是一個閉包函數的結構, 看 num( ) 返回的列表里面放的應該是四個 bar 函數的內存地址 : [bar, bar, bar, bar] , 並沒有去調用 bar 函數

def num():
    # 返回值是一個列表生成式, 里面存放了四個而函數對象
    return [lambda x: x * i for i in range(4)]

for i in num():
    print(i)
'''
<function num.<locals>.<listcomp>.<lambda> at 0x000002AA99D2CE58>
<function num.<locals>.<listcomp>.<lambda> at 0x000002AA99D2CDC8>
<function num.<locals>.<listcomp>.<lambda> at 0x000002AA99EE4708>
<function num.<locals>.<listcomp>.<lambda> at 0x000002AA99EE4D38>
'''

當執行print([func(2) for func in num()]) 的時候, 這才觸發了每個 bar 函數的執行, 此時的 for 循環已經結束了, 最終的 i = 3, 所以每次的結果都是 2*3=6

非匿名函數解決方法

# 直接在匿名函數內綁定默認參數i
def num():
    return [lambda x,n=i: x * n for i in range(4)]

print([func(2) for func in num()])  # [0, 2, 4, 6]

非匿名函數解決方法

在內層函數 bar 形參位置設置一個接收 i 的參數, 讓其綁定

def num():
    sub=[]
    for i in range(4):
        def bar(x,n=i):
            return n*x
        sub.append(bar)
    return sub

print([func(2) for func in num()])  # [0, 2, 4, 6]

閉包函數延遲綁定問題解釋

在函數嵌套的時候, 如果一個循環返回的是一個函數對象, 該函數對象出現引用的時候並不會立即引用循環的值, 而是在運行(調用)嵌套函數的時候才會去查找該引用的值, 這個特性就是閉包函數的延遲綁定


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM