將變數封裝在閉包中以將其從函數簽章中刪除是一種常用於高效代碼結構的技術。但是,在非嵌套 lambda 的情況下,閉包保留變數的最終值,從而在嘗試基於迭代變數存取特定值時導致問題。
考慮提供的程式碼片段:
names = ['a', 'b', 'c'] def test_fun(name, x): print(name, x) def gen_clousure(name): return lambda x: test_fun(name, x) funcs1 = [gen_clousure(n) for n in names] funcs2 = [lambda x: test_fun(n, x) for n in names] # Expected output for funcs1 for f in funcs1: f(1) # Unexpected output for funcs2 (returns last element for all cases) for f in funcs2: f(1)
理解這種差異背後的原因對於有效利用閉包至關重要。
這種情況下的基本概念是閉包中的變數作用域。閉包本質上保存的是變數名稱,而不是它們的值。這表示變數的求值發生在 lambda 執行啟動時,而不是在 lambda 定義時。
對於 funcs2,當您執行 lambda x: test_fun(n, x) 時,變數 n在 lambda 定義期間不進行評估。相反,評估僅在 lambda 呼叫時發生。此時,n 保存循環中的最後一個值(在本例中為「c」)。因此,函數 f 總是使用“c”作為 n 的值,而不管輸入 x。
要解決此問題並實現所需的功能,必須在 lambda 函數的作用域中捕獲變數 n。這可以透過將變數作為參數傳遞給lambda 來實現,如下所示:
funcs2 = [lambda x: test_fun(n, x) for n in names if 2 > 0]
透過包含這個始終成立的附加if 語句,我們強制lambda 將n 的值作為參數,確保在所有情況下實現預期的個人化行為。
或者,您可以將非嵌套 lambda 包裝在嵌套函數中,有效防止存取作用域中未聲明的變數。下面的程式碼說明了這個方法:
def makeFunc(n): return lambda x: x n stuff = [makeFunc(n) for n in [1, 2, 3]] for f in stuff: print(f(1))
這裡,變數 n 在函數 makeFunc 中捕獲,確保 lambda 內的作用域正確。
理解和管理變數作用域in 閉包對於有效的程式碼設計和調試至關重要。關鍵要點是:
免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。
Copyright© 2022 湘ICP备2022001581号-3