Einführung
In diesem Abschnitt wird die Idee der Verwendung von Funktionen zur Erstellung anderer Funktionen vorgestellt.
This tutorial is from open-source community. Access the source code
💡 Dieser Artikel wurde von AI-Assistenten übersetzt. Um die englische Version anzuzeigen, können Sie hier klicken
In diesem Abschnitt wird die Idee der Verwendung von Funktionen zur Erstellung anderer Funktionen vorgestellt.
Betrachten Sie die folgende Funktion.
def add(x, y):
def do_add():
print('Adding', x, y)
return x + y
return do_add
Dies ist eine Funktion, die eine andere Funktion zurückgibt.
>>> a = add(3,4)
>>> a
<function add.<locals>.do_add at 0x7f27d8a38790>
>>> a()
Adding 3 4
7
Beobachten Sie, wie die innere Funktion auf Variablen verweist, die von der äußeren Funktion definiert wurden.
def add(x, y):
def do_add():
## `x` und `y` sind oberhalb von `add(x, y)` definiert
print('Adding', x, y)
return x + y
return do_add
Beobachten Sie weiter, dass diese Variablen irgendwie am Leben bleiben, nachdem add()
abgeschlossen ist.
>>> a = add(3,4)
>>> a
<function do_add at 0x6a670>
>>> a()
Adding 3 4 ## Woher kommen diese Werte?
7
Wenn eine innere Funktion als Ergebnis zurückgegeben wird, ist diese innere Funktion als Closure bekannt.
def add(x, y):
## `do_add` ist ein Closure
def do_add():
print('Adding', x, y)
return x + y
return do_add
Wesentliches Merkmal: Ein Closure behält die Werte aller Variablen bei, die das spätere ordnungsgemäße Ausführen der Funktion erforderlich macht. Denken Sie sich ein Closure als eine Funktion plus eine zusätzliche Umgebung, die die Werte der Variablen enthält, auf die es angewiesen ist.
Closures sind ein wesentliches Merkmal von Python. Ihre Verwendung ist jedoch oft subtil. Allgemeine Anwendungen:
Betrachten Sie eine Funktion wie diese:
def after(seconds, func):
import time
time.sleep(seconds)
func()
Verwendungsbeispiel:
def greeting():
print('Hello Guido')
after(30, greeting)
after
führt die bereitgestellte Funktion... später aus.
Closures tragen zusätzliche Informationen mit sich.
def add(x, y):
def do_add():
print(f'Adding {x} + {y} -> {x+y}')
return do_add
def after(seconds, func):
import time
time.sleep(seconds)
func()
after(30, add(2, 3))
## `do_add` hat die Referenzen x -> 2 und y -> 3
Closures können auch als Technik zur Vermeidung von übermäßiger Code-Wiederholung verwendet werden. Sie können Funktionen schreiben, die Code erzeugen.
Eine der leistungsfähigsten Eigenschaften von Closures ist ihre Verwendung bei der Erzeugung von wiederholendem Code. Wenn Sie sich an Übung 5.7 erinnern, denken Sie an den Code zur Definition einer Eigenschaft mit Typüberprüfung.
class Stock:
def __init__(self, name, shares, price):
self.name = name
self.shares = shares
self.price = price
...
@property
def shares(self):
return self._shares
@shares.setter
def shares(self, value):
if not isinstance(value, int):
raise TypeError('Expected int')
self._shares = value
...
Anstatt diesen Code immer wieder zu tippen, können Sie ihn mithilfe eines Closures automatisch erstellen.
Erstellen Sie eine Datei typedproperty.py
und legen Sie den folgenden Code darin ab:
## typedproperty.py
def typedproperty(name, expected_type):
private_name = '_' + name
@property
def prop(self):
return getattr(self, private_name)
@prop.setter
def prop(self, value):
if not isinstance(value, expected_type):
raise TypeError(f'Expected {expected_type}')
setattr(self, private_name, value)
return prop
Versuchen Sie es nun, indem Sie eine Klasse wie diese definieren:
from typedproperty import typedproperty
class Stock:
name = typedproperty('name', str)
shares = typedproperty('shares', int)
price = typedproperty('price', float)
def __init__(self, name, shares, price):
self.name = name
self.shares = shares
self.price = price
Versuchen Sie, eine Instanz zu erstellen und zu überprüfen, ob die Typüberprüfung funktioniert.
>>> s = Stock('IBM', 50, 91.1)
>>> s.name
'IBM'
>>> s.shares = '100'
... sollte einen TypeError erzeugen...
>>>
Im obigen Beispiel könnten Benutzer die Aufrufe wie typedproperty('shares', int)
als etwas umständlich bei der Eingabe empfinden - insbesondere wenn sie oft wiederholt werden. Fügen Sie die folgenden Definitionen zur typedproperty.py
-Datei hinzu:
String = lambda name: typedproperty(name, str)
Integer = lambda name: typedproperty(name, int)
Float = lambda name: typedproperty(name, float)
Nehmen Sie nun die Stock
-Klasse auf und verwenden Sie stattdessen diese Funktionen:
class Stock:
name = String('name')
shares = Integer('shares')
price = Float('price')
def __init__(self, name, shares, price):
self.name = name
self.shares = shares
self.price = price
Ah, das ist etwas besser. Der wichtigste Punkt hier ist, dass Closures und lambda
oft verwendet werden können, um Code zu vereinfachen und lästige Wiederholungen zu eliminieren. Dies ist oft vorteilhaft.
Herzlichen Glückwunsch! Sie haben das Lab "Returning Functions" abgeschlossen. Sie können in LabEx weitere Labs ausprobieren, um Ihre Fähigkeiten zu verbessern.