Ich habe viel über Verschlüsse gelesen und glaube, ich verstehe sie, aber ohne das Bild für mich und andere zu trüben, hoffe ich, dass jemand Verschlüsse so kurz und klar wie möglich erklären kann. Ich suche nach einer einfachen Erklärung, die mir helfen könnte zu verstehen, wo und warum ich sie verwenden möchte.
python
functional-programming
closures
bekannter Bürger
quelle
quelle
nonlocal
Python 2.x in Python 3 hinzugefügt wurde und keine vollständigen Lese- / Schreibabschlüsse hatte (dh Sie konnten geschlossene Variablen lesen, aber ihre Werte nicht ändern)nonlocal
Schlüsselwort in Python 2 mithilfe eines veränderlichen Objekts emulieren, z. B. könnenL = [0] \n def counter(): L[0] += 1; return L[0]
Sie den Namen in diesem Fall nicht ändern (an ein anderes Objekt binden), aber Sie können das veränderbare Objekt selbst ändern, auf das sich der Name bezieht zu. Die Liste ist erforderlich, da Ganzzahlen in Python unveränderlich sind.Es ist ganz einfach: Eine Funktion, die auf Variablen aus einem enthaltenen Bereich verweist, möglicherweise nachdem der Kontrollfluss diesen Bereich verlassen hat. Das letzte bisschen ist sehr nützlich:
Beachten Sie, dass 12 und 4 in f bzw. g "verschwunden" sind. Diese Funktion macht f und g zu richtigen Verschlüssen.
quelle
constant = x
; Sie könnten dies einfachreturn y + x
in der verschachtelten Funktion tun (oder das Argument mit dem Namen erhaltenconstant
), und es würde gut funktionieren. Argumente werden von der Schließung nicht anders erfasst als nicht argumentative Einheimische.Ich mag diese grobe, prägnante Definition :
Ich würde hinzufügen
Dekorateure, die Parameter akzeptieren, werden häufig für Verschlüsse verwendet. Closures sind ein gängiger Implementierungsmechanismus für diese Art von "Function Factory". Ich verwende häufig Abschlüsse im Strategiemuster, wenn die Strategie zur Laufzeit durch Daten geändert wird.
In einer Sprache, die eine anonyme Blockdefinition ermöglicht - z. B. Ruby, C # - können Verschlüsse verwendet werden, um neuartige neue Kontrollstrukturen zu implementieren (wie viel). Das Fehlen anonymer Blöcke gehört zu den Einschränkungen von Schließungen in Python .
quelle
Um ehrlich zu sein, verstehe ich Verschlüsse sehr gut, außer dass mir nie klar war, was genau das ist, was der "Verschluss" ist und was so "Verschluss" daran ist. Ich empfehle Ihnen, die Suche nach einer Logik für die Wahl des Begriffs aufzugeben.
Wie auch immer, hier ist meine Erklärung:
Eine Schlüsselidee hierbei ist, dass das von foo zurückgegebene Funktionsobjekt einen Hook für die lokale Variable 'x' behält, obwohl 'x' den Gültigkeitsbereich verlassen hat und nicht mehr gültig sein sollte. Dieser Hook bezieht sich auf die Variable selbst, nicht nur auf den Wert, den var zu diesem Zeitpunkt hatte. Wenn also bar aufgerufen wird, wird 5 und nicht 3 ausgegeben.
Stellen Sie außerdem klar, dass Python 2.x nur einen begrenzten Abschluss hat: Ich kann 'x' in 'bar' auf keinen Fall ändern, da durch das Schreiben von 'x = bla' ein lokales 'x' in bar deklariert und nicht 'x' von foo zugewiesen wird . Dies ist ein Nebeneffekt von Pythons Zuweisung = Deklaration. Um dies zu umgehen, führt Python 3.0 das nichtlokale Schlüsselwort ein:
quelle
Ich habe noch nie von Transaktionen gehört, die im selben Kontext wie die Erklärung eines Abschlusses verwendet werden, und hier gibt es wirklich keine Transaktionssemantik.
Es wird als Abschluss bezeichnet, weil es die äußere Variable (Konstante) "schließt" - dh es ist nicht nur eine Funktion, sondern ein Gehäuse der Umgebung, in der die Funktion erstellt wurde.
Im folgenden Beispiel ändert das Aufrufen des Abschlusses g nach dem Ändern von x auch den Wert von x innerhalb von g, da g über x schließt:
quelle
g()
berechnet esx * 2
, gibt aber nichts zurück. Das sollte seinreturn x * 2
. +1 dennoch für eine Erklärung für das Wort "Schließung".Hier ist ein typischer Anwendungsfall für Schließungen - Rückrufe für GUI-Elemente (dies wäre eine Alternative zur Unterklasse der Schaltflächenklasse). Sie können beispielsweise eine Funktion erstellen, die als Reaktion auf einen Tastendruck aufgerufen wird, und die relevanten Variablen im übergeordneten Bereich, die für die Verarbeitung des Klicks erforderlich sind, "schließen". Auf diese Weise können Sie ziemlich komplizierte Schnittstellen über dieselbe Initialisierungsfunktion verkabeln und alle Abhängigkeiten in den Abschluss einbauen.
quelle
In Python ist ein Abschluss eine Instanz einer Funktion, an die Variablen unveränderlich gebunden sind.
Tatsächlich erklärt das Datenmodell dies in seiner Beschreibung des Funktionsattributs
__closure__
:Um dies zu demonstrieren:
Es ist klar, dass wir jetzt eine Funktion haben, auf die der Variablenname zeigt
closure_instance
. Wenn wir es mit einem Objekt aufrufen, sollte es angeblichbar
die Zeichenfolge drucken'foo'
und unabhängig von der Zeichenfolgendarstellungbar
.In der Tat, die Zeichenfolge ‚foo‘ wird auf die Instanz der Funktion gebunden, und wir können es direkt hier lesen, indem Sie den Zugriff auf
cell_contents
Attribut des ersten (und einzigen) Zelle in dem Tupel des__closure__
Attributs:Nebenbei werden Zellobjekte in der C-API-Dokumentation beschrieben:
Und wir können die Verwendung unseres Verschlusses demonstrieren, indem wir feststellen, dass
'foo'
er in der Funktion steckt und sich nicht ändert:Und nichts kann es ändern:
Teilfunktionen
In dem angegebenen Beispiel wird der Verschluss als Teilfunktion verwendet. Wenn dies jedoch unser einziges Ziel ist, kann dasselbe Ziel erreicht werden
functools.partial
Es gibt auch kompliziertere Verschlüsse, die nicht zum Teilfunktionsbeispiel passen, und ich werde sie weiter demonstrieren, wenn es die Zeit erlaubt.
quelle
Hier ist ein Beispiel für Python3-Schließungen
quelle
Von Closures zu erfüllende Kriterien sind:
quelle
Für mich sind "Verschlüsse" Funktionen, die sich an die Umgebung erinnern können, in der sie erstellt wurden. Mit dieser Funktion können Sie Variablen oder Methoden innerhalb des Abschlusses verwenden, die Sie auf andere Weise nicht verwenden können, weil sie nicht mehr vorhanden sind oder aufgrund des Umfangs nicht erreichbar sind. Schauen wir uns diesen Code in Ruby an:
Es funktioniert auch dann, wenn sowohl die "Multiplikations" -Methode als auch die "x" -Variable nicht mehr vorhanden sind. Alles nur, weil die Schließfähigkeit in Erinnerung bleibt.
quelle
Wir alle haben Decorators in Python verwendet. Sie sind schöne Beispiele, um zu zeigen, was Schließfunktionen in Python sind.
hier ist der Endwert 12
Hier kann die Wrapper-Funktion auf das func-Objekt zugreifen, da der Wrapper "lexikalischer Abschluss" ist und auf die übergeordneten Attribute zugreifen kann. Aus diesem Grund kann auf func-Objekte zugegriffen werden.
quelle
Ich möchte mein Beispiel und eine Erklärung zu Schließungen mitteilen. Ich habe ein Python-Beispiel und zwei Abbildungen gemacht, um die Stapelzustände zu demonstrieren.
Die Ausgabe dieses Codes wäre wie folgt:
Hier sind zwei Abbildungen, die Stapel und den am Funktionsobjekt angebrachten Verschluss zeigen.
wenn die Funktion vom Hersteller zurückgegeben wird
wenn die Funktion später aufgerufen wird
Wenn die Funktion über einen Parameter oder eine nichtlokale Variable aufgerufen wird, benötigt der Code lokale Variablenbindungen wie margin_top, padding sowie a, b, n. Um sicherzustellen, dass der Funktionscode funktioniert, sollte auf den Stapelrahmen der Maker-Funktion zugegriffen werden können, der vor langer Zeit entfernt wurde. Dies wird in dem Abschluss gesichert, den wir zusammen mit dem Funktionsobjekt der Nachricht finden.
quelle
Die beste Erklärung, die ich je für einen Verschluss gesehen habe, war die Erklärung des Mechanismus. Es ging ungefähr so:
Stellen Sie sich Ihren Programmstapel als einen entarteten Baum vor, in dem jeder Knoten nur ein untergeordnetes Element hat und der einzelne Blattknoten den Kontext Ihrer aktuell ausgeführten Prozedur darstellt.
Lockern Sie nun die Einschränkung, dass jeder Knoten nur ein Kind haben kann.
Wenn Sie dies tun, können Sie ein Konstrukt ('Ausbeute') haben, das von einer Prozedur zurückkehren kann, ohne den lokalen Kontext zu verwerfen (dh es wird bei Ihrer Rückkehr nicht vom Stapel genommen). Beim nächsten Aufruf der Prozedur nimmt der Aufruf den alten Stapelrahmen (Baumrahmen) auf und setzt die Ausführung dort fort, wo er aufgehört hat.
quelle