Python Closures

Table of Contents

 

In diesem Tutorial erfahren Sie, was eine Python Closure ist, wie Sie eine Closure definieren und warum Sie sie verwenden sollten.

 

Nonlocal variable in a nested function

 

Bevor wir uns damit beschäftigen, was eine Schließung ist, müssen wir zunächst verstehen, was eine verschachtelte Funktion und eine nicht-lokale Variable ist.

Eine Funktion, die innerhalb einer anderen Funktion definiert ist, wird als verschachtelte Funktion bezeichnet. Verschachtelte Funktionen können auf Variablen des umschließenden Bereichs zugreifen.

In Python sind diese nicht-lokalen Variablen standardmäßig schreibgeschützt und wir müssen sie explizit als nicht-lokal deklarieren (mit dem Schlüsselwort nonlocal), um sie zu verändern.

Es folgt ein Beispiel für eine verschachtelte Funktion, die auf eine nicht-lokale Variable zugreift.

 

def print_msg(msg):
    # Dies ist die äußere umschließende Funktion

    def printer():
        # Dies ist die nested  Funktion
        print(msg)

    printer()

# Wir führen die Funktion
# Output: Hello
print_msg("Hello")

 

Output

Hello

 

 

Wir können sehen, dass die verschachtelte printer() Funktion konnte auf die nicht-lokale msg Variable der einschließenden Funktion.

 


 

Defining a Closure Function

 

 

Was würde im obigen Beispiel passieren, wenn die letzte Zeile der Funktion print_msg() returned die printer() Funktion, anstatt sie aufzurufen? Das bedeutet, dass die Funktion wie folgt definiert wurde:

def print_msg(msg):
    # Dies ist die äußere umschließende Funktion

    def printer():
        # Dies ist die nested Funktion
        print(msg)

    return printer  # returns die nested Funktion
 

# Versuchen wir nun, diese Funktion aufzurufen.
# Output: Hello
another = print_msg("Hello")
another()

 

Output

Hello

 

Das ist ungewöhnlich.

 

Die print_msg() Funktion wurde mit der Zeichenkette "Hello" und die returned Funktion wurde an den Namen another. Bei Anruf another(), wurde die Meldung immer noch gespeichert, obwohl wir bereits die Ausführung der print_msg() Funktion.

 

Diese Technik, mit der einige Daten ("Hello in diesem Fall) an den Code angehängt wird, heißt closure in Python.

Dieser Wert im umschließenden Bereich wird auch dann beibehalten, wenn die Variable aus dem Bereich geht oder die Funktion selbst aus dem aktuellen Namensraum entfernt wird.

Versuchen Sie, das Folgende in der Python-Shell auszuführen, um die Ausgabe zu sehen.

>>> del print_msg
>>> another()
Hello
>>> print_msg("Hello")
Traceback (most recent call last):
...
NameError: name 'print_msg' is not defined

 

Hier funktioniert die zurückgegebene Funktion auch dann noch, wenn die ursprüngliche Funktion gelöscht wurde.

 


 

 

When do we have closures?

Wie aus dem obigen Beispiel ersichtlich, haben wir in Python eine Closure, wenn eine verschachtelte Funktion einen Wert in ihrem umschließenden Bereich referenziert.

 

Die Kriterien, die erfüllt sein müssen, um einen Abschluss in Python zu erstellen, sind in den folgenden Punkten zusammengefasst.

 

  • Wir müssen eine nested Funktion (Funktion innerhalb einer Funktion) haben.
  • Die nested Funktion muss sich auf einen Wert beziehen, der in der einschließenden Funktion definiert ist.
  • Die umschließende Funktion muss die verschachtelte Funktion zurückgeben.

 


 

 

When to use closures?

Wofür sind Closures also gut?

Closures können die Verwendung von globalen Werten vermeiden und bieten eine Form des Datenversteckens. Sie können auch eine objektorientierte Lösung für das Problem bieten.

Wenn es nur wenige Methoden (in den meisten Fällen eine Methode) gibt, die in einer Klasse implementiert werden müssen, können Closures eine alternative und elegantere Lösung bieten. Aber wenn die Anzahl der Attribute und Methoden größer wird, ist es besser, eine Klasse zu implementieren.

Hier ist ein einfaches Beispiel, bei dem eine Closure vorzuziehen ist, anstatt eine Klasse zu definieren und Objekte zu erstellen. Aber die Vorliebe liegt ganz bei Ihnen.

def make_multiplier_of(n):
    def multiplier(x):
        return x * n
    return multiplier


# Multiplier of 3
times3 = make_multiplier_of(3)

# Multiplier of 5
times5 = make_multiplier_of(5)

# Output: 27
print(times3(9))

# Output: 15
print(times5(3))

# Output: 30
print(times5(times3(2)))

 

Output

27
15
30

 

 

Python Decorators machen ebenfalls ausgiebigen Gebrauch von Closures.

Abschließend ist es gut, darauf hinzuweisen, dass die Werte, die in der Closure-Funktion eingeschlossen werden, herausgefunden werden können.

 

Alle Funktions Objekte haben eine __closure__ Attribut, das ein Tupel von Zellobjekten zurückgibt, wenn es sich um eine Abschlussfunktion handelt. Bezogen auf das obige Beispiel wissen wir times3 und times5 sind closure Funktionen.

>>> make_multiplier_of.__closure__
>>> times3.__closure__
(<cell at 0x0000000002D155B8: int object at 0x000000001E39B6E0>,)

 

Das Objekt cell hat das Attribut cell_contents, das den geschlossenen Wert speichert.

>>> times3.__closure__[0].cell_contents
3
>>> times5.__closure__[0].cell_contents
5