【python】閉包

閉包

所謂閉包,就是將組成函數(shù)的語(yǔ)句和這些語(yǔ)句的執(zhí)行環(huán)境打包在一起時(shí),得到的對(duì)象。

  • 栗子1
def count():
    fs = []
    for i in range(1, 4):
        def f():
             return i*i
        fs.append(f) #這里的 f 已經(jīng)是一個(gè)函數(shù) 加入了
    return fs
f1, f2, f3 = count()
>>> f1()
9
>>> f2()
9
>>> f3()
9

上面這個(gè)函數(shù)有點(diǎn)糾結(jié)!
糾結(jié)點(diǎn)1:f1, f2, f3 = count()是什么意思?
:f1, f2, f3 = count() 這個(gè)并不是我猜想3個(gè)都平等同樣的指向fs這個(gè)list,更有可能的是,這個(gè)三個(gè)這是分別指向了list中的3個(gè)元素
(1)只有元素才有可能是int
(2)如果只寫(xiě)成f1,f2 = count()的話
會(huì)報(bào)錯(cuò)ValueError: too many values to unpack (expected 2)
寫(xiě)成f1,f2,f3,f4= count()的話
會(huì)報(bào)錯(cuò)ValueError: need more than 3 values to unpack
(3)打印出來(lái)看

>>>print(f1,f2,f3)
返回3個(gè)<function count.<locals>.f at 0x00000000037F5400>
>>>f1= count
>>>print(f1())
[<function count.<locals>.f at 0x0000000002F65268>,
<function count.<locals>.f at 0x0000000002F65400>,
<function count.<locals>.f at 0x0000000002F65488>]

說(shuō)明,如果返回一個(gè)列表,那么這個(gè)列表每個(gè)元素都是函數(shù)。
糾結(jié)點(diǎn)2:為什么f1(),f2(),f3()都返回9,即為啥列表中的元素都是9?
原因是返回函數(shù)引用了變量i,下面來(lái)解析下f1,f2,f3=count()這句的執(zhí)行過(guò)程:
  當(dāng)i=1, 執(zhí)行for循環(huán), 結(jié)果返回函數(shù)f的函數(shù)地址,存在列表fs中的第一個(gè)位置上。
   當(dāng)i=2, 由于fs列表中第一個(gè)元素所指的函數(shù)中的i是count函數(shù)的局部變量,i也指向了2;然后執(zhí)行for循環(huán), 結(jié)果返回函數(shù)f的函數(shù)地址,存在列表fs中的第二個(gè)位置上。
  當(dāng)i=3, 同理,在fs列表第一個(gè)和第二個(gè)元素所指的函數(shù)中的i變量指向了3; 然后執(zhí)行for循環(huán), 結(jié)果返回函數(shù)f的函數(shù)地址,存在列表fs中的第三個(gè)位置上。
  所以在調(diào)用f1()的時(shí)候,函數(shù)中的i是指向3的:
f1():
  return 3*3
同理f2(), f3()結(jié)果都為9

注意:返回閉包時(shí)牢記的一點(diǎn)就是:返回函數(shù)不要引用任何循環(huán)變量,或者后續(xù)會(huì)發(fā)生變化的變量。
  • 栗子2:如果一定要引用循環(huán)變量怎么辦?方法是再創(chuàng)建一個(gè)函數(shù),用該函數(shù)的參數(shù)綁定循環(huán)變量當(dāng)前的值,無(wú)論該循環(huán)變量后續(xù)如何更改,已綁定到函數(shù)參數(shù)的值不變:
def count():
    def f(j):
        def g():
            return j*j
        return g
    fs = []
    for i in range(1, 4):
        fs.append(f(i)) # f(i)立刻被執(zhí)行,因此i的當(dāng)前值被傳入f()
    return fs

注意:當(dāng)i=1時(shí),f(1)即讓j指向1,f(1)立即被執(zhí)行,返回值是g函數(shù),g函數(shù)作為參數(shù)傳入fs.append()里
當(dāng)i=2時(shí),f(2)即讓j指向2,此時(shí)j不是count的局部變量,不會(huì)影響到i=1是f(1)中j的指向。即函數(shù)f的參數(shù)綁定循環(huán)變量當(dāng)前的值, 而不是循環(huán)變量本身。

>>> f1, f2, f3 = count()
>>> f1()
1
>>> f2()
4
>>> f3()
9
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容