python基礎知識之函式初階——閉包

格瑞姆瑞坡發表於2019-02-16

什麼是閉包?

其實我們在使用函式過程中不經意間就會觸發閉包,因為總會出於某種原因會在函式內引用或修改上一層函式的變數,這時就會觸發閉包

那麼什麼是閉包?其實就是函式巢狀時觸發的一種規則,當前函式引用到上一層函式的區域性名稱空間的變數並且函式本身被當成物件返回時就觸發該規則。
我們說觸發了閉包的函式叫做閉包函式

閉包最大的特點就是它可以被外層函式返回後賦值給一個變數,並且攜帶了外層函式內定義的變數

例子如下:

def func1():
    a = 2  #變數a為函式func1()開闢的區域性名稱空間內定義的變數
    def func2(x):
        return x**a  #函式fun2()內引用了變數a
    print(`func2的id:`,id(func2))
    return func2 #內層函式名被當作返回值,此時閉包規則達成。
res = func1() # 此時res等同於func2,我們可以看看他們的id完全相同
print(`res的id:  `,id(res))
print(res(3))
del func1
print(`刪除函式func1之後:`,res(5))
print(res.__closure__) 
print(type(res.__closure__[0])) 
print(res.__closure__[0].cell_contents) 
#此時,如果函式func2()沒有引用外部函式變數a,我們可以試著把return x**a這句改成return x,這時函式func2就沒有觸發閉包規則
#此時如果再次列印res.__closure__,你會發現輸出值為None

從下面輸出結果可以看出,即使刪除了函式func1,理論上應該消失的變數a依然可以使用(理論上a對應的區域性空間消失了,則a應消失),變數a之所以仍然可以被引用,是因為閉包規則的作用,外部函式的區域性變數可以被內部函式引用,即使外部函式已經返回了。
其實函式本身也是物件,而物件又有很多屬性,其中和閉包相關的就是 closure 屬性。
closure 屬性定義的是一個包含 cell 物件的元組,其中元組中的每一個 cell 物件用來儲存作用域中變數的值。

func2的id: 139940709362136
res的id:   139940709362136
9
刪除函式func1之後: 25
#我們來列印一下res的__closure__屬性,可以看出它是由cell物件組成的元組
(<cell at 0x7f467c4a8558: int object at 0x5654c2553a40>,)
<class `cell`> #列印型別結果就是元組
2  #列印cell中的值可以看出,這個cell物件中儲存的變數值為2

觸發閉包後,實現了引用上層區域性名稱空間變數的同時又不依賴於該區域性空間,即使該變數所在的函式被刪除了,閉包函式依然可以使用它,實際上閉包函式把它儲存在了__closure__屬性中。

相關文章