Wo ein Name lebt
Der Gültigkeitsbereich (Scope) eines Namens ist der Teil des Programms, in dem er verwendet werden kann. Ein in einer Funktion angelegter Name ist lokal: Er existiert nur, solange die Funktion läuft, und ist außerhalb unsichtbar. Ein Name auf oberster Ebene der Datei ist global: Funktionen können ihn lesen. Trifft Python auf einen Namen, sucht es zuerst in der Funktion, dann in umgebenden Funktionen, dann in der Datei, dann in den eingebauten Namen.
rate = 0.001 # global: defined outside any function
def fee(notional):
minimum = 1.0 # local: exists only during the call
return max(minimum, notional * rate)
print(fee(36850.0)) # 36.85
# print(minimum) # would raise NameError: minimum is not definedZuweisen erzeugt einen lokalen Namen
Einen globalen Namen in einer Funktion zu lesen ist in Ordnung. Aber Zuweisen an einen Namen in einer Funktion erzeugt einen neuen lokalen Namen, selbst wenn ein globaler gleichen Namens existiert: Der globale bleibt unberührt. Das schützt Ihre Daten, und es ist auch der Grund, warum das Ändern globalen Zustands aus einer Funktion zusätzliche Wörter (global) braucht, die Sie selten brauchen sollten. Übergeben Sie Werte als Argumente und geben Sie Ergebnisse mit return zurück.
# Assigning inside a function makes a new local name
balance = 1000
def deposit(amount):
balance = amount # a different, local balance
return balance
print(deposit(50)) # 50
print(balance) # 1000 (the global one is unchanged)Funktionen, die Funktionen erzeugen
Eine Funktion kann in sich eine weitere Funktion definieren und per return zurückgeben. Die innere Funktion behält Zugriff auf die Variablen der äußeren, auch nachdem die äußere beendet ist. Dieses Bündel aus Funktion und gemerkten Werten ist eine Closure. Sie ist ein sauberer Weg, aus Einstellungen ein fertiges Werkzeug zu bauen: ein Rechner für Aktien, ein anderer für ETFs.
# A closure remembers the variables of the function that made it
def make_fee_calculator(rate, minimum):
def fee(notional):
return max(minimum, notional * rate)
return fee
stock_fee = make_fee_calculator(0.001, 1.0)
etf_fee = make_fee_calculator(0.0005, 0.5)
print(stock_fee(36850.0)) # 36.85
print(etf_fee(36850.0)) # 18.425Zustand zwischen Aufrufen: nonlocal
Eine Closure kann das Gemerkte auch ändern. Da eine Zuweisung einen neuen lokalen Namen anlegen würde, deklariert die innere Funktion zuerst nonlocal count: „Dieser Name gehört zur umgebenden Funktion“. Jeder Aufruf der äußeren Funktion erzeugt einen eigenen Speicher, sodass sich zwei Zähler nie stören. So behält ein Order-ID-Generator oder ein gleitender Durchschnitt seinen Zustand ohne globale Variable.
# nonlocal lets the inner function rebind the outer variable
def make_counter():
count = 0
def next_id():
nonlocal count
count += 1
return count
return next_id
order_ids = make_counter()
print(order_ids(), order_ids(), order_ids()) # 1 2 3
other = make_counter()
print(other()) # 1 (its own count)# State between calls: an exponential moving average
def make_ema(alpha):
value = None
def update(price):
nonlocal value
value = price if value is None else alpha * price + (1 - alpha) * value
return value
return update
ema = make_ema(0.5)
print(ema(100.0), ema(110.0), ema(110.0)) # 100.0 105.0 107.5- In einer Funktion sind zugewiesene Namen lokal; Daten hineingeben, per
returnherausgeben. - Eine Funktion, die eine Funktion baut und zurückgibt, verpackt Einstellungen zu einem Werkzeug.
- Nutzen Sie
nonlocalfür Zustand, der zwischen Aufrufen erhalten bleiben muss, ein Speicher pro Closure.
Als Nächstes: List Comprehensions, um aus einer Liste in einer einzigen lesbaren Zeile eine neue zu bauen.
Lab: Was bewertet wird
- Mit
make_countereinen Zähler bauen, der sich seinen Stand merkt25 Pkt. - Mit
make_fee_calculatorGebühreneinstellungen in eine Funktion packen25 Pkt. - Mit
make_emaeinen gleitenden Durchschnitt zwischen Aufrufen halten25 Pkt. - Mit
make_limit_checkeraus einer Grenze eine Preisprüfung erzeugen25 Pkt.