跳至主要内容

Closure 是什麼?

寫程式的時候,偶爾會聽到「Closure」這個詞。

這不是什麼陌生的概念。我們常常在用,只是不一定意識到它的名字。

函式是第一類物件

在 Python 裡,函式不只是語法糖的工具,而是具備完整權能的物件。

你可以:

  • 將函式指派給變數
  • 將它當作參數傳遞
  • 從另一個函式中將它作為結果回傳
def greet(name):
return f"Hello, {name}"

say_hello = greet
print(say_hello("Alice"))
# => Hello, Alice

這意味著函式可以像資料一樣被操作,也能與其他邏輯共構,形成模組化的行為單位。

作用域中的函式生成

Python 允許在函式內部定義其他函式,形成巢狀的結構:

def outer():
def inner():
print("Hello from the inside")
inner()

在這裡,inner() 僅能在 outer() 的作用域中存活,外部無法直接呼叫。

但我們可以換個方式撰寫,改變它的命運:

  • 將函式作為結果傳遞

    def outer():
    def inner():
    print("I’m still alive.")
    return inner

    escaped = outer()
    escaped() # => I’m still alive.

在這段程式碼中,雖然 outer() 已經結束,但 inner() 仍可被呼叫。

原因在於 inner() 被「帶出來」的同時,也攜帶了它需要的執行上下文。

Closure

終於來到主題了。

Closure 是一種語言機制,允許函式捕捉其外部作用域中的變數,並在函式結束後仍然能夠使用這些變數。

下面看一個例子:

def make_multiplier(factor):
def multiply(n):
return n * factor
return multiply

triple = make_multiplier(3)
double = make_multiplier(2)

print(triple(10)) # 30
print(double(10)) # 20

在這裡,factormultiply() 的自由變數:

  • 它不是在 multiply() 的內部定義,但被用到了。

make_multiplier() 執行結束後,這個 factor 並沒有消失。

它被「封裝」在 multiply() 裡,一起被返回。

這樣的組合,就是所謂的 Closure

如何辨認 Closure?

可以從函式的 __closure__ 屬性來觀察:

>>> triple.__closure__
(<cell at 0x...: int object at 0x...>,)

>>> [c.cell_contents for c in triple.__closure__]
[3]
  • __closure__ 會列出函式中被捕捉的自由變數
  • cell_contents 取出這些變數的實際內容

這不是什麼神秘現象,只是一種語言機制的自然結果。

常見用途與場景

  • 函式工廠:根據輸入參數產出具狀態的自訂函式
  • 計數器/快取:保留有限狀態,避免額外開 class
  • 裝飾器 (@decorator):常見的實作方式就是基於 Closure 結構疊加
  • 依賴注入:將資料隱性地綁定,避免污染全域狀態

當你需要 保存少量狀態、又不想動用完整物件導向設計時,Closure 是一個恰到好處的工具。

小結

Closure 不難懂,它的本質只是:

  1. 捕捉:將自由變數的值保存下來
  2. 打包:與函式本體一同封裝
  3. 延續:即使原始作用域不再,仍能正常運作

當你遇到 __closure__,不需要驚訝。它只是當時環境的一個封存版本,保留了那一刻的資料狀態。

這些值像是程式的記憶片段,陪著函式一起前行。

☕ 一杯咖啡,就是我創作的燃料!

贊助我持續分享 AI 實作、全端架構與開源經驗,讓好文章不斷更新。

cta-button
AI / 全端 / 客製 一次搞定 icon
ALL

AI / 全端 / 客製 一次搞定

從構想到上線,涵蓋顧問、開發與部署,全方位支援你的技術實作。

包含內容
  • 顧問服務 + 系統建置 + 客製開發
  • 長期維運與擴充規劃

🚀 你的專案準備好了嗎?

如果你需要客製服務或長期顧問,歡迎與我聯繫!