什麼是閉包?
閉包, 英文爲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_var
在inner_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))
這樣雖然可能需要多敲幾個字母, 但代碼的可維護性大大增加. 所以, 閉包對於我來說, 瞭解下概念就行, 儘量不用.