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

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

先看下面這個函數:python

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], 百思不得其解, 咱們先來把匿名函數變成普通函數, 這樣好理解一點 :app

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=6code

非匿名函數解決方法

在內層函數 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]

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

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

相關文章
相關標籤/搜索