Closures sind ein mächtiger Mechanismus in Python, der es ermöglicht, Funktionen mit "gespeicherten" Daten aus dem umgebenden Kontext zu erstellen.
In funktionalen Programmiersprachen und in Python sind Funktionen erstklassige Objekte. Eine Funktion kann eine neue Funktion zurückgeben, die Variablen aus ihrem umgebenden (äußeren) Geltungsbereich "schließt".
Entwickler sind oft verwirrt darüber, wie genau geschlossene Variablen innerhalb eines Closures "leben", wenn sie gelesen oder geschrieben werden, und wie man sicher mit ihnen umgeht (insbesondere mit veränderbaren Objekten).
Wenn eine innere Funktion Variablen der äußeren Funktion verwendet, werden diese automatisch "gemerkt" — selbst wenn die äußere Funktion bereits abgeschlossen ist. Das Lesen einer Variablen ist offensichtlich, aber wenn man den Wert ändern möchte, muss das Schlüsselwort nonlocal verwendet werden. Bei der Arbeit mit veränderbaren Objekten (Listen, Dictionaries) ist dies ein besonderer Risikobereich.
Beispiel:
def outer(): count = 0 def inner(): nonlocal count count += 1 return count return inner counter = outer() print(counter()) # 1 print(counter()) # 2
Wichtige Merkmale:
nonlocal (ansonsten wird eine lokale Variable erstellt).Kann man den Wert einer geschlossenen Variablen innerhalb einer Funktion ohne nonlocal ändern?
Nein. Wenn Sie versuchen, einen neuen Wert zuzuweisen, ohne nonlocal anzugeben, betrachtet Python dies als Erstellung einer neuen lokalen Variablen, und der alte Wert wird nicht nach außen gehen.
Beispiel:
def make_counter(): count = 0 def inner(): count += 1 # Fehler UnboundLocalError! return count return inner
Kann man Argumente durch ein Closure in den äußeren Scope übergeben?
Ja, Closures "merken" sich alle Variablen, die im äußeren Geltungsbereich verfügbar sind, einschließlich Klassenattributen, globalen Variablen usw. Das Ändern dieser Variablen erfordert jedoch besonderen Aufwand (z. B. die Verwendung von nonlocal oder global).
Was passiert mit veränderbaren Objekten innerhalb eines Closures?
Wenn eine geschlossene Variable auf ein veränderbares Objekt verweist, z. B. eine Liste, können Sie seinen Inhalt ohne nonlocal ändern, aber wenn Sie versuchen, die Variable neu zuzuweisen, ist nonlocal erforderlich.
Beispiel:
def make_appender(): result = [] def append(x): result.append(x) # Ist erlaubt! return result return append f = make_appender() print(f(1)) # [1] print(f(2)) # [1, 2]
Ein Entwickler schreibt ein Closure, ändert eine Variable ohne nonlocal — es tritt ein UnboundLocalError auf.
Vorteile:
Nachteile:
Eindeutige Verwendung von nonlocal für einen kontrollierten Zustand in Closures.
Vorteile:
Nachteile: