Python 的閉包

什麼是閉包?

閉包, 英文爲closure.
首先, 閉包是一種特殊的函數. 特殊之處在於它包含了非本地也非全局的自由變量.

def outer_fn():
    outer_var = []
    def inner_fn(val):
        outer_var.append(val)
        return sum(outer_var) * 1.0 / len(outer_var)
    return inner_fn

在上面的代碼中, inner_fn就是一個閉包函數. 對inner_fn來說, outer_var既非它的本地變量, 也非全局變量, 而是outer_fn的本地變量.

實現原理

按照道理來說, outer_fn的本地變量在程序退出函數體後會被自動銷燬回收, 但因爲outer_varinner_fn內被引用了, 所以它不會被銷燬, 而是成爲一個自由變量. 可是, 在執行inner_fn的主體代碼時, outer_var存儲在哪呢? 在fn對象的__closure__屬性裏:

fn = outer_fn()
print(fn(10))
print ('fn.__closure__:', fn.__closure__[0].cell_contents)
print(fn(20))
print ('fn.__closure__:', fn.__closure__[0].cell_contents)

輸出爲:

10.0
fn.__closure__: [10]
15.0
fn.__closure__: [10, 20]

有什麼用?

也許有用, 例如在修飾器中, 但並非不可缺少. 引入閉包實際是給函數對象引入了狀態, 然後呢, 導致相同的輸入不一定能得到相同的輸出, 感覺有點彆扭. 所以, 如果需要保存狀態, 可以通過面向對象方式來實現. 例如上面的代碼可使用class 封裝:

class Cls():
    def __init__(self):
        self.var = []

    def fn(self, val):
        self.var.append(val)
        return sum(self.var) * 1.0 / len(self.var)

inst = Cls()
print(inst.fn(10))
print(inst.fn(20))

這樣雖然可能需要多敲幾個字母, 但代碼的可維護性大大增加. 所以, 閉包對於我來說, 瞭解下概念就行, 儘量不用.

發佈了103 篇原創文章 · 獲贊 157 · 訪問量 58萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章