巢狀函數提供了一種在更廣泛的上下文中組織程式碼和封裝功能的便捷方法。然而,了解如何在巢狀作用域內處理變數通常會讓開發人員感到困惑。
考慮以下程式碼片段:
class Cage(object): def __init__(self, animal): self.animal = animal def get_petters(): for animal in ['cow', 'dog', 'cat']: cage = Cage(animal) def pet_function(): print("Mary pets the " + cage.animal + ".") yield (animal, cage.animal)
在此範例中,產生器函數get_petters() 迭代動物列表,為每個動物建立一個Cage 對象,並產生一個包含動物名稱的元組和一個嘗試存取籠子本地的巢狀函數變數。
執行此程式碼後,您可能會期望看到列印三種不同的動物,對應於籠子變數的三個不同實例。然而,輸出僅重複地產生“Mary pets the cat”。
問題的癥結在於Python中閉包的本質。定義巢狀函數時,它們會捕獲對其封閉範圍內的變數的引用。在提供的程式碼中,pet_function 嵌套在 get_petters() 函數中,因此可以存取籠變數。
但是,在函數定義時並未建立此參考。相反,它發生在函數執行時。執行巢狀函數時,籠子變數在遍歷動物清單時已被指派值「cat」。
要解決此問題,可以用幾種方法:
1.部分函數:
部分函數是一個可呼叫函數,它包裝現有函數並使用預設值初始化其一些參數。在這種情況下,您可以使用 functools.partial() 建立一個部分 pet 函數,將籠變數綁定到適當的上下文:
def pet_function(cage=None): print("Mary pets the " + cage.animal + ".") yield (animal, partial(pet_function, cage=cage))
2。建立新作用域:
另一個選項是在巢狀作用域內定義pet 函數,以確保籠變數始終在本機綁定到正確的值:
def scoped_cage(cage=None): def pet_function(): print("Mary pets the " + cage.animal + ".") return pet_function yield (animal, partial(pet_function, cage))
3.預設關鍵字參數:
您也可以將籠子變數當作預設關鍵字參數傳遞給pet函數:
def pet_function(cage=cage): print("Mary pets the " + cage.animal + ".") yield (animal, partial(pet_function))
透過遵循這些技術,您可以確保巢狀函數使用預期的局部變數進行操作,消除意外的副作用並保持程式碼清晰度。
以上是為什麼 Python 中的巢狀函數僅存取循環變數的最後一個值?的詳細內容。更多資訊請關注PHP中文網其他相關文章!