-
Notifications
You must be signed in to change notification settings - Fork 71
05b ClosureData
ccckmit edited this page Dec 4, 2024
·
1 revision
本章將探討如何使用 閉包 (Closure) 在函數內部儲存資料,並解析閉包的本質、特性以及其在函數式程式設計中的應用。閉包是一種強大的工具,能讓我們在無需使用類別的情況下創建狀態保持的函數。
-
定義
- 閉包是一個函數,該函數「記住」了它所在的作用域中的變數,即使該作用域已經結束。
- 簡單來說,閉包讓函數具備「攜帶環境」的能力。
-
範例:普通函數 vs 閉包
# 普通函數 def add(x, y): return x + y print(add(2, 3)) # 輸出 5 # 閉包範例 def make_adder(x): def adder(y): return x + y return adder add_5 = make_adder(5) print(add_5(10)) # 輸出 15
-
閉包的條件
- 必須有內嵌函數。
- 內嵌函數必須使用外部作用域中的變數。
- 外部函數的執行結束後,內嵌函數仍然可存取外部變數。
-
模擬物件的行為
- 閉包提供了類似物件的狀態儲存方式,但更加輕量化。
def counter(): count = 0 def increment(): nonlocal count count += 1 return count return increment c = counter() print(c()) # 輸出 1 print(c()) # 輸出 2
- 閉包提供了類似物件的狀態儲存方式,但更加輕量化。
-
避免全域變數污染
- 閉包允許我們在函數中封裝狀態,避免使用全域變數。
def multiplier(factor): def multiply(number): return number * factor return multiply double = multiplier(2) triple = multiplier(3) print(double(5)) # 輸出 10 print(triple(5)) # 輸出 15
- 閉包允許我們在函數中封裝狀態,避免使用全域變數。
-
延遲求值 (Lazy Evaluation)
- 使用閉包儲存運算的中間狀態,推遲計算以提升效能。
-
作用域鏈與自由變數
- 自由變數 (Free Variable):不是在本地作用域中定義的變數,但可被函數存取。
- Python 中閉包會將自由變數儲存在
__closure__
屬性中。
範例:
def outer_function(x): def inner_function(y): return x + y return inner_function closure_fn = outer_function(10) print(closure_fn(5)) # 輸出 15 print(closure_fn.__closure__[0].cell_contents) # 輸出 10
-
nonlocal
關鍵字- 當內部函數需要修改外部作用域的變數時,需使用
nonlocal
聲明。def counter(): count = 0 def increment(): nonlocal count count += 1 return count return increment c = counter() print(c()) # 輸出 1 print(c()) # 輸出 2
- 當內部函數需要修改外部作用域的變數時,需使用
-
閉包的效能注意事項
- 過多的閉包可能導致記憶體使用效率低下,因為閉包會保留其作用域的變數。
-
記錄器 (Logger)
- 使用閉包封裝日誌設定。
def logger(level): def log(message): print(f"[{level}] {message}") return log info_logger = logger("INFO") error_logger = logger("ERROR") info_logger("This is an info message.") # 輸出 [INFO] This is an info message. error_logger("This is an error message.") # 輸出 [ERROR] This is an error message.
- 使用閉包封裝日誌設定。
-
函數裝飾器
- 閉包是實現裝飾器的核心技術。
def decorator(func): def wrapper(*args, **kwargs): print("Before calling the function") result = func(*args, **kwargs) print("After calling the function") return result return wrapper @decorator def say_hello(name): print(f"Hello, {name}!") say_hello("Alice")
- 閉包是實現裝飾器的核心技術。
-
快取機制 (Memoization)
- 閉包可用於儲存運算結果,避免重複計算。
def memoize(func): cache = {} def wrapper(x): if x not in cache: cache[x] = func(x) return cache[x] return wrapper @memoize def fibonacci(n): if n <= 1: return n return fibonacci(n - 1) + fibonacci(n - 2) print(fibonacci(10)) # 輸出 55
- 閉包可用於儲存運算結果,避免重複計算。
-
複雜性
- 過度使用閉包可能導致程式碼可讀性降低。
-
記憶體開銷
- 閉包會持續引用其外部作用域變數,可能導致不必要的記憶體佔用。
-
調試困難
- 閉包的作用域鏈可能難以追蹤,特別是在多層嵌套的情況下。
閉包是 Python 中非常靈活且實用的工具,能夠封裝狀態並提供延遲計算、模組化與輕量級物件的替代方案。透過閉包,我們可以避免全域變數污染、簡化高階函數應用,並實現如裝飾器、快取等實用模式。然而,在實際應用中需注意閉包的效能問題與過度複雜性,確保程式碼保持簡潔與高效。
從希爾伯特到圖靈的那些故事
-- 以 Python 展現這些故事背後的程式