閉包 = 函數 + 其捕獲的自由變數環境。Python 2 需用可變容器 (列表) 模擬非區域賦值,Python 3 引入 nonlocal 關鍵字直接支援。本文詳細解析閉包機制與三大應用模式。
def make_adder(addend):
def adder(augend):
return augend + addend
return adder
p = make_adder(23)
q = make_adder(44)
print(p(100)) # 123
print(q(100)) # 144
addend 被內部函數捕獲,形成閉包。每次呼叫 make_adder 產生新環境,互不干擾。
def counter():
count = [0]
def inc():
count[0] += 1
return count[0]
return inc
def counter():
count = 0
def inc():
nonlocal count
count += 1
return count
return inc
def makebold(fn):
def wrapped():
return "" + fn() + ""
return wrapped
def makeitalic(fn):
def wrapped():
return "" + fn() + ""
return wrapped
@makebold
@makeitalic
def hello():
return "hello world"
print(hello()) # hello world
裝飾器本質是接受函數、回傳增強函數的閉包。
def later(fn, *args, **kwargs):
def thunk():
return fn(*args, **kwargs)
return thunk
task = later(print, "deferred")
task() # 輸出: deferred
| 特性 | 閉包 | 類別 |
|---|---|---|
| 語法 | 輕量、函數式 | 結構化、物件導向 |
| 狀態 | 捕獲外部變數 | 實例屬性 |
| 多方法 | 需回傳多函數或字典 | 天然支援 |
| 繼承 | 不支援 | 支援 |
funcs = []
for i in range(3):
funcs.append(lambda: i)
print([f() for f in funcs]) # [2, 2, 2] 全捕獲同一 i
# 修正: lambda i=i: i 或 functools.partial
def f(x, lst=[]): # lst 只建立一次
lst.append(x)
return lst
閉包是函數式程式設計核心概念,善用能大幅簡化狀態管理程式碼。