Kurs
Es ist echt nervig, wenn man nach ein paar Zeilen Programmcode die Meldungen „Name ist nicht definiert“ oder „Lokale Variable vor Zuweisung referenziert“ sieht. Der Code sieht gut aus, aber Python findet das anders. Das Problem liegt meistens im Geltungsbereich: wo ein Name zu sehen ist und auf welches Objekt er sich gerade bezieht.
Sobald du die Namenssuche in Python verstehst – oft als LEGB-Regel zusammengefasst –, sind diese Fehler vorhersehbar und leicht zu beheben. In diesem Tutorial erkläre ich dir Schritt für Schritt Variablen und Gültigkeitsbereiche in Python.
Was ist eine Variable?
Eine Variable ist ein Name, der mit einem Objekt verbunden ist. In Python machst du eine Bindung mit dem Zuweisungsoperator ` =`. Namen werden nicht eingegeben; sie können auf jedes Objekt zeigen (Zeichenfolge, Ganzzahl, Liste, Funktion usw.).
customer_name = "Ava Torres"
order_count = 1
total_cents = 1 + 2 * 300 # evaluated first, then bound
Befolge diese Regeln und Konventionen bei der Benennung von Variablen, um Syntaxfehler und versteckte Fehler zu vermeiden.
- Benutz nur Buchstaben, Zahlen und Unterstriche; Namen dürfen nicht mit einer Zahl anfangen.
- Verwende keine Stichwörter wie „
True“, „for“ oder „class“ als Namen.
- Vermeide es, eingebaute Funktionen wie „
list“, „dict“, „sum“ oder „max“ zu überschreiben.
- Verwende lieber „
snake_case“, damit es besser lesbar ist (PEP 8).
Diese Beispiele zeigen, was man nicht machen sollte und welche Fehler Python auslöst:
first string value = "First string" # spaces not allowed
# SyntaxError: invalid syntax
1st_value = 10 # cannot start with a digit
# SyntaxError: invalid decimal literal
True = "yes" # cannot assign to a keyword
# SyntaxError: cannot assign to True
Wie Python Scope funktioniert (LEGB)
Der Geltungsbereich ist der Bereich im Code, in dem ein Name sichtbar ist. Wenn du einen Namen benutzt, sucht Python ihn in dieser Reihenfolge (LEGB):
- Lokal: der Bereich der aktuellen Funktion.
- Umschließt: alle äußeren Funktionsbereiche (für verschachtelte Funktionen).
- Global: die oberste Ebene des Moduls (Modul-Namespace).
- Eingebaut: Namen, die Python in „
builtins“ definiert hat (zum Beispiel „len“, „print“).
Namen sind in Namensräumen (stell dir Wörterbücher vor, die Namen mit Objekten verbinden). Der Geltungsbereich bestimmt, welche Namespaces Python durchsucht, um einen Namen an einer bestimmten Stelle im Code aufzulösen.
Lokaler Geltungsbereich
Innerhalb einer Funktion zugewiesene Namen sind lokal für diese Funktion, sofern nicht anders angegeben. Sie sind außerhalb der Funktion nicht sichtbar.
def show_order_id():
order_id = 42
print("inside function:", order_id)
show_order_id()
print("outside function:", order_id) # NameError
Python legt den Geltungsbereich beim Kompilieren fest. Wenn eine Funktion irgendwo in ihrem Körper einem Namen einen Wert zuweist, werden alle Verwendungen dieses Namens in der Funktion als lokal behandelt – was zu einem häufigen Fehler „ UnboundLocalError ” führt, wenn du vor der Zuweisung liest:
discount_rate = 0.10 # module-level (global)
def price_with_discount(amount_cents):
print("configured discount:", discount_rate) # looks local because of the assignment below
discount_rate = 0.20 # assignment makes 'discount_rate' local in this function
return int(amount_cents * (1 - discount_rate))
# UnboundLocalError: cannot access local variable 'discount_rate' where it is not associated with a value
Um den Namen auf Modulebene in der Funktion zu verwenden, solltest du entweder keine Zuweisung vornehmen oder ihn als „ global “ kennzeichnen (siehe unten).
Umschließender Bereich (Umschließungen)
Verschachtelte Funktionen können Namen aus der Funktion sehen, die sie direkt umgibt. Um so einen Namen neu zu binden (nicht nur zu lesen), mach das so: ` nonlocal`.
def make_step_counter():
count = 0 # enclosing scope for 'increment'
def increment():
nonlocal count # rebind the 'count' in the nearest enclosing function
count += 1
return count
return increment
step = make_step_counter()
print(step()) # 1
print(step()) # 2
Ohne „ nonlocal “ würde die Zuweisung zu „ count “ innerhalb von „ increment() “ einen neuen lokalen Namen erstellen und den äußeren „ count “ unverändert lassen.
Weltweite Reichweite
Die Namen, die auf der obersten Ebene eines Moduls vergeben werden, sind im globalen Namensraum des Moduls. Jede Funktion kann sie lesen. Um einen Namen auf Modulebene innerhalb einer Funktion zuzuweisen, musst du ihn mit ` global` deklarieren.
greeting = "Hello"
def greet_city(city_name):
print(greeting, city_name) # reads global
def set_greeting(new_greeting):
global greeting
greeting = new_greeting # rebinds global
greet_city("Nairobi") # Hello Nairobi
set_greeting("Hi")
greet_city("Nairobi") # Hi Nairobi
Benutz „ global “ nur ab und zu. Gib lieber Werte als Parameter weiter und gib Ergebnisse zurück, damit der Code testbar und vorhersehbar bleibt.
Eingebauter Bereich (und ein Hinweis zu Schlüsselwörtern)
Der eingebaute Bereich hat Namen wie „ len “, „ print “ und „ Exception “. Vermeide es, sie zu beschatten, sonst verlierst du den Zugriff auf das integrierte für diesen Bereich.
list = [1, 2, 3] # shadows the built-in 'list' constructor
list("abc") # TypeError: 'list' object is not callable
del list # fix by deleting the shadowing name
Schlüsselwörter (wie if, for, def) sind Teil der Syntax von Python, nicht des integrierten Namensraums, und können nie als Bezeichner verwendet werden.
Blöcke, Schleifen und Comprehensions
Die Blockanweisungen und Comprehensions von Python haben bestimmte Verhaltensweisen beim Geltungsbereich, die Entwickler, die von anderen Sprachen kommen, oft überraschen.
Es gibt keinen Blockbereich für if/for/while/with
Zuweisungen innerhalb dieser Blöcke beeinflussen den enthaltenen Bereich (Funktion oder Modul). Schleifenvariablen bleiben auch nach dem Ende der Schleife definiert.
if True:
status = "ready"
print(status) # "ready"
for i in range(3):
pass
print(i) # 2 (the last value from the loop)
Comprehensions machen ihre Iterationsvariable unabhängig
Listen-, Dict- und Set-Comprehensions haben ihren eigenen lokalen Geltungsbereich für Schleifenvariablen. Die Iterationsvariable wird nicht in den umgebenden Bereich weitergegeben.
numbers = [1, 2, 3]
[x for x in numbers]
print("x" in globals() or "x" in locals()) # False
Python 3.12 (PEP 709) hat Inline-Comprehensions eingebaut, um die Geschwindigkeit zu erhöhen und gleichzeitig diese Isolation zu behalten. Du bekommst immer noch klare, nicht auslaufende Schleifenvariablen mit schnellerer Ausführung.
Mit dem global Schlüsselwort
Deklarier einen Namen als „ global “ innerhalb einer Funktion, wenn du eine Variable auf Modulebene neu binden musst. Schreib die Deklaration oben in die Funktion, damit klar ist, welche Variable du änderst.
tax_rate = 0.08
def configure_tax(rate):
global tax_rate
tax_rate = float(rate)
def total_with_tax(cents):
return int(cents * (1 + tax_rate))
configure_tax(0.10)
print(total_with_tax(1000)) # 1100
Mit dem nonlocal Schlüsselwort
Benutz„ nonlocal “, um einen Namen aus dem nächsten umschließenden Funktionsbereich neu zu binden. Das ist bei Closures, die den Zustand beibehalten, ganz normal.
def make_accumulator(start=0):
total = start
def add(amount):
nonlocal total
total += amount
return total
return add
acc = make_accumulator()
print(acc(5)) # 5
print(acc(10)) # 15
Wenn du „ nonlocal ” für einen Namen benutzt, der nicht in einer umschließenden Funktion definiert ist, ist das ein Fehler namens „ SyntaxError ”. Wenn der Name global ist, nimm stattdessen global.
locals() und globals() im Jahr 2025
Die Funktionen „“ sind praktisch für die Überprüfung und Fehlerbehebung, aber nicht zum Aktualisieren von Variablen. Ab Python 3.13 (PEP 667) gibt jeder Aufruf von ` ` `locals()` ` ` in einer Funktion einen eigenen Snapshot zurück. Das Bearbeiten dieses Snapshots ändert nichts an den echten lokalen Variablen. Ich habe dieses Verhalten bestätigt, indem ich den folgenden Codeausschnitt unter Python 3.13 ausgeführt habe:
def probe():
project = "alpha"
snap1 = locals()
snap1["project"] = "beta" # edits the snapshot only
observed = project # still "alpha"
snap2 = locals() # new snapshot
return snap1["project"], observed, snap2["project"]
print(probe()) # ('beta', 'alpha', 'alpha')
Benutze „ globals() ” genauso für den Modul-Namespace. Verwende beim Schreiben von Anwendungscode lieber explizite Parameter und Rückgabewerte als dynamische Lookups.
Häufige Probleme und wie man sie löst
Diese Fehler machen die meisten Probleme aus, die ich in der Praxis mit dem Umfang sehe.
UnboundLocalErroraus der Zuweisung in einer Funktion: Python sieht einen Namen als lokal an, wenn er irgendwo in der Funktions-on zugewiesen wird. Verschieb das Lesen nach der Zuweisung, benenn es um oder füge global/nonlocal hinzu, je nachdem, was passt.
- Erwarteter Blockbereich: Die Namen, die in if/for/while/with zugewiesen werden, bleiben im enthaltenen Bereich. Benutze strengere Hilfsfunktionen, um den Umfang zu begrenzen.
- Eingebaute Schatten: Vermeide ID-Namen wie „list“, „dict“, „sum“, „id“ oder „min“. Nimm lieber beschreibende Namen wie „
customer_list“ oder „min_allowed“.
nonlocal-Vergessen in Closures: Wenn du eine Variable in einer äußeren Funktion aktualisieren willst (), musst du sie als nicht lokal deklarieren. Sonst machst du eine neue lokale Variable und der äußere Wert ändert sich nicht.
- Verwirrende Schlüsselwörter mit integrierten Funktionen: Schlüsselwörter (Syntax) können niemals als Namen verwendet werden. Eingebaute Elemente können ausgeblendet werden, sollten es aber nicht.
Bewährte Methoden, die den Umfang überschaubar halten
Diese Gewohnheiten machen den Code einfacher zu lesen, zu testen und zu debuggen.
- Bevorzugt kleine, fokussierte Funktionen. Variablen im kleinstmöglichen Umfang definieren, der funktioniert.
- Daten über Parameter und Rückgabewerte rein- und rausgeben. Minimier den Status auf Modulebene.
- Benutz Closures bewusst. Dokumentiere, welchen äußeren Namen „” als verschachtelte Funktion erfasst, und benutze „nonlocal”, wenn du wirklich neu binden musst.
- Wähle beschreibende, nicht widersprüchliche Namen. Ein führender Unterstrich (zum Beispiel
_cache) zeigt an, dass es für interne Zwecke gedacht ist.
- Behandlelocals()/globals() als Diagnosefunktionen, die man nicht ändern kann, und nicht als Konfigurationsmechanismus.
Fazit
Python sucht Namen in diesen Reihen: lokal → umgebend → global → eingebaut. Wenn du diese Reihenfolge verstehst – und weißt, wann du global oder nicht lokal verwenden musst – vermeidest du häufige Fehler wie „ NameError “ und „ UnboundLocalError “. Halt Variablen so klein wie möglich, vermeid das Überschreiben von integrierten Funktionen und setz Closures bewusst ein. Mit diesem mentalen Modell verhalten sich deine Funktionen vorhersehbar, und der Geltungsbereich sorgt nicht mehr für Überraschungen.

Ich habe in verschiedenen Branchen gearbeitet und mehrere Aufgaben übernommen: Softwareentwickler, Forscher für maschinelles Lernen, Datenwissenschaftler und Produktmanager. Aber im Grunde bin ich ein Programmierer, der es liebt, zu lernen und sein Wissen zu teilen!