524 Stimmen

Kurze Beschreibung der Geltungsbereichsregeln

Was sind genau die Python-Bereichsbereiche?

Wenn ich etwas Code habe:

code1
class Foo:
   code2
   def spam.....
      code3
      for code4..:
       code5
       x()

Wo wird x gefunden? Einige mögliche Optionen sind unten aufgeführt:

  1. Im umgebenden Quellcode
  2. Im Klassenbereich
  3. In der Funktionsdefinition
  4. In der Schleifenindexvariable
  5. Innerhalb der Schleife

Auch gibt es den Kontext während der Ausführung, wenn die Funktion spam an anderer Stelle übergeben wird. Und vielleicht werden Lambda-Funktionen etwas anders übergeben?

Es muss irgendwo eine einfache Referenz oder Algorithmus geben. Es ist eine verwirrende Welt für fortgeschrittene Python-Programmierer.

4 Stimmen

Die Geltungsbereichsregeln werden ziemlich knapp, aber auch vollständig, in der Python-Dokumentation beschrieben: docs.python.org/3/reference/….

451voto

Rizwan Kassim Punkte 7619

Eigentlich eine prägnante Regel für die Python Scope-Auflösung, aus Learning Python, 3. Auflage. (Diese Regeln beziehen sich speziell auf Variablennamen, nicht auf Attribute. Wenn Sie es ohne einen Punkt referenzieren, gelten diese Regeln.)

LEGB Regel

  • Local - Namen, die in einer Funktion (def oder lambda) auf irgendeine Weise zugewiesen werden und nicht in dieser Funktion global deklariert sind

  • Enclosing-function - Namen, die im lokalen Bereich aller statisch umschließenden Funktionen (def oder lambda) von innen nach außen zugewiesen werden

  • Global (Modul) - Namen, die in der obersten Ebene einer Moduldatei zugewiesen werden oder durch Ausführen einer global-Anweisung in einem def in der Datei

  • Built-in (Python) - Vordefinierte Namen im integrierten Namensmodul: open, range, SyntaxError, usw.

Also, im Fall von

code1
class Foo:
    code2
    def spam():
        code3
        for code4:
            code5
            x()

Die for-Schleife hat keinen eigenen Namespace. In LEGB-Reihenfolge wären die Bereiche

  • L: Lokal in def spam (in code3, code4 und code5)
  • E: Alle umschließenden Funktionen (wenn das gesamte Beispiel in einem anderen def wäre)
  • G: Gab es irgendwelche global deklarierten x im Modul (in code1)?
  • B: Irgendwelche integrierten x in Python.

x wird niemals in code2 gefunden (auch in Fällen, in denen Sie erwarten könnten, dass es so ist, siehe Antwort von Antti oder hier).

50 Stimmen

Als Vorbehalt zum globalen Zugriff - das Lesen einer globalen Variablen kann ohne explizite Deklaration erfolgen, das Schreiben an sie ohne Erklärung von global(var_name) wird jedoch stattdessen eine neue lokale Instanz erstellen.

12 Stimmen

Eigentlich @Peter, global(var_name) ist syntaktisch inkorrekt. Die richtige Syntax wäre global var_name ohne Klammern. Du hast jedoch einen validen Punkt.

0 Stimmen

Wenn ja, warum ist dann die "y" Variable von "foo" nicht für "bar" unten sichtbar: >>> def foo(x): ... y = x ... def bar(z): ... y = z ... bar(5) ... print x,y ... >>> foo(3) 3 3

161voto

Brian Punkte 112487

Im Wesentlichen ist die einzige Sache in Python, die einen neuen Gültigkeitsbereich einführt, eine Funktionsdefinition. Klassen sind ein Sonderfall, da alles, was direkt im Körper definiert ist, im Namensraum der Klasse platziert wird, aber nicht direkt aus den Methoden (oder verschachtelten Klassen), die sie enthalten, zugänglich ist.

In Ihrem Beispiel gibt es nur 3 Bereiche, in denen nach x gesucht wird:

  • Gültigkeitsbereich von spam - enthält alles, was in code3 und code5 definiert ist (sowie code4, Ihre Schleifenvariable)

  • Der globale Gültigkeitsbereich - enthält alles, was in code1 definiert ist, sowie Foo (und was auch immer danach geändert wird)

  • Der eingebaute Namensraum. Ein Sonderfall - enthält die verschiedenen Python-eigenen Funktionen und Typen wie len() und str(). Im Allgemeinen sollte dieser Bereich nicht von Benutzercode geändert werden, daher erwarten Sie, dass er die Standardfunktionen und nichts anderes enthält.

Weitere Gültigkeitsbereiche erscheinen nur, wenn Sie eine verschachtelte Funktion (oder Lambda) ins Spiel bringen. Diese verhalten sich jedoch weitgehend wie erwartet. Die verschachtelte Funktion kann auf alles im lokalen Bereich, sowie auf alles im umgebenden Funktionbereich zugreifen. z.B.

def foo():
    x=4
    def bar():
        print x  # Zugriff auf x aus dem Bereich von foo
    bar()  # Gibt 4 aus
    x=5
    bar()  # Gibt 5 aus

Einschränkungen:

Variablen in Gültigkeitsbereichen, die nicht die Variablen der lokalen Funktion sind, können abgerufen werden, dürfen jedoch ohne weitere Syntax nicht an neue Parameter gebunden werden. Stattdessen wird durch die Zuweisung eine neue lokale Variable anstelle der Beeinflussung der Variable im übergeordneten Gültigkeitsbereich erstellt. Zum Beispiel:

global_var1 = []
global_var2 = 1

def func():
    # Das ist in Ordnung: Es wird nur abgerufen, nicht neu gebunden
    global_var1.append(4) 

    # Dies wird global_var2 nicht beeinflussen. Es wird stattdessen eine neue Variable erstellt
    global_var2 = 2 

    local1 = 4
    def embedded_func():
        # Auch dies beeinträchtigt nicht die lokale Variable local1 von func. Es wird stattdessen eine neue lokale Variable namens local1 erstellt.
        local1 = 5
        print local1

    embedded_func() # Gibt 5 aus
    print local1    # Gibt 4 aus

Um tatsächlich die Bindungen von globalen Variablen innerhalb eines Funktionsbereichs zu ändern, müssen Sie angeben, dass die Variable global ist, mit dem Schlüsselwort global. Z.B.:

global_var = 4
def change_global():
    global global_var
    global_var = global_var + 1

Derzeit gibt es keine Möglichkeit, dasselbe für Variablen in umgebenden _Funktions_bereichen zu tun, aber Python 3 führt ein neues Schlüsselwort ein, "nonlocal", das ähnlich wie global wirkt, aber für verschachtelte Funktionenbereiche.

121voto

Es gab keine gründliche Antwort bezüglich Python3-Zeit, also habe ich hier eine Antwort gemacht. Das meiste, was hier beschrieben wird, ist im 4.2.2 Auflösung von Namen der Python 3-Dokumentation detailliert beschrieben.

Wie in anderen Antworten angegeben, gibt es 4 grundlegende Bereiche, die LEGB, für Lokal, Schließende, Globale und Eingebaute. Zusätzlich dazu existiert ein spezieller Bereich, der Klassenbereich, der keinen umschließenden Bereich für Methoden definiert, die innerhalb der Klasse definiert wurden; jegliche Zuweisungen innerhalb des Klassenbereichs lassen die Variable von nun an im Klassenbereich gebunden sein.

Insbesondere erstellt keine Blockanweisung außer def und class einen Variablenspeicher. In Python 2 erstellt eine Listenverständlichkeit keinen Variablenspeicher, jedoch wird in Python 3 die Schleifenvariable innerhalb von Listenverständnissen in einem neuen Bereich erstellt.

Um die Besonderheiten des Klassenbereichs zu demonstrieren

x = 0
class X(object):
    y = x
    x = x + 1 # x ist jetzt eine Variable
    z = x

    def method(self):
        print(self.x) # -> 1
        print(x)      # -> 0, das globale x
        print(y)      # -> NameError: globaler Name 'y' ist nicht definiert

inst = X()
print(inst.x, inst.y, inst.z, x) # -> (1, 0, 1, 0)

So können im Klassenbereich im Gegensatz zum Funktionsbereich die Variable mit demselben Namen erneut zugewiesen werden, um eine Klassenvariable mit demselben Namen zu erhalten; weitere Nachschlagen dieses Namens lösen auf die Klassenvariable.


Eine der größten Überraschungen für viele Neueinsteiger in Python ist, dass eine for-Schleife keinen Variablenspeicher erstellt. In Python 2 erstellen auch Listenverständnisse keinen Bereich (während Generatoren und Dictionary-Verständnisse dies tun!) Stattdessen geben sie den Wert in den Funktions- oder globalen Bereich frei:

>>> [ i for i in range(5) ]
>>> i
4

Die Verständnisse können als raffinierter (oder schrecklicher, wenn Sie so wollen) Weg verwendet werden, um modifizierbare Variablen innerhalb von Lambda-Ausdrücken in Python 2 zu erstellen - ein Lambda-Ausdruck erstellt einen Variablenspeicher, wie die def-Anweisung, allerdings sind in Lambda keine Anweisungen erlaubt. Da Zuweisung in Python eine Anweisung ist, bedeutet dies, dass keine Variablenzuweisungen in Lambda erlaubt sind, jedoch ein Listenverständnis ein Ausdruck ist...

Dieses Verhalten wurde in Python 3 behoben - keine Verständnisausdrücke oder Generatoren geben Variablen frei.


Global bedeutet wirklich der Modulbereich; das Haupt-Python-Modul ist das __main__; alle importierten Module sind über die Variable sys.modules zugänglich; um auf __main__ zuzugreifen, kann man sys.modules['__main__'] verwenden oder import __main__; es ist vollkommen akzeptabel, Attribute dort abzurufen und zuzuweisen; sie erscheinen als Variablen im globalen Bereich des Hauptmoduls.


Wenn ein Name jemals im aktuellen Bereich zugewiesen wird (außer im Klassenbereich), wird er als zu diesem Bereich gehörend betrachtet, ansonsten wird davon ausgegangen, dass er zu einem umschließenden Bereich gehört, der der Variable Zuweisungen zuweist (es kann sein, dass diese noch nicht zugewiesen wurde oder überhaupt nicht), oder schließlich zum globalen Bereich. Wenn die Variable als lokal betrachtet wird, aber noch nicht festgelegt wurde oder gelöscht wurde, führt das Lesen des Variablenwerts zu UnboundLocalError, was eine Unterklasse von NameError ist.

x = 5
def foobar():
    print(x)  # führt zu UnboundLocalError!
    x += 1    # da Zuweisung hier x zu einer lokalen Variable innerhalb der Funktion macht

# Funktion aufrufen
foobar()

Der Bereich kann explizit angeben, dass er die globale (Modulbereich) Variable ändern möchte, mit dem globalen Schlüsselwort:

x = 5
def foobar():
    global x
    print(x)
    x += 1

foobar() # -> 5
print(x) # -> 6

Dies ist auch möglich, wenn sie im umgebenden Bereich überlagert wurde:

x = 5
y = 13
def make_closure():
    x = 42
    y = 911
    def func():
        global x # sieht den globalen Wert
        print(x, y)
        x += 1

    return func

func = make_closure()
func()      # -> 5 911
print(x, y) # -> 6 13

In Python-2 gibt es keinen einfachen Weg, den Wert im umgebenden Bereich zu ändern; normalerweise wird dies simuliert, indem ein veränderlicher Wert verwendet wird, wie eine Liste mit einer Länge von 1:

def make_closure():
    value = [0]
    def get_next_value():
        value[0] += 1
        return value[0]

    return get_next_value

get_next = make_closure()
print(get_next()) # -> 1
print(get_next()) # -> 2

In Python 3 kommt jedoch nonlocal zur Rettung:

def make_closure():
    value = 0
    def get_next_value():
        nonlocal value
        value += 1
        return value
    return get_next_value

get_next = make_closure() # identisches Verhalten wie im vorherigen Beispiel.

Die nonlocal-Dokumentation besagt, dass

Namen, die in einer nonlocal-Anweisung aufgeführt sind, im Gegensatz zu denen, die in einer globalen Anweisung aufgeführt sind, müssen sich auf bereits bestehende Bindungen in einem umschließenden Bereich beziehen (der Bereich, in dem eine neue Bindung erstellt werden sollte, kann nicht eindeutig bestimmt werden).

d.h. nonlocal bezieht sich immer auf den am engsten umgebenen äußeren nicht-globalen Bereich, in dem der Name gebunden wurde (d.h. zugewiesen wurde, einschließlich Verwendung als Zielvariable von for, in der with-Klausel oder als Funktionsparameter).


Jede Variable, die nicht als lokal für den aktuellen Bereich oder einen umgebenden Bereich angesehen wird, ist eine globale Variable. Ein globaler Name wird im globalen Wörterbuch des Moduls gesucht; wenn nicht gefunden, wird der globale Name dann aus dem builtins-Modul gesucht; der Name des Moduls wurde von Python 2 auf Python 3 geändert; in Python 2 war es __builtin__ und in Python 3 heißt es jetzt builtins. Wenn Sie ein Attribut des builtins-Moduls zuweisen, ist es danach für jedes Modul als lesbarer globaler Schreibzugriff sichtbar, es sei denn, das Modul überschattet sie mit seinem eigenen globalen Namen mit demselben Namen.


Das Lesen des builtins-Moduls kann auch nützlich sein; nehmen wir an, Sie wollen die Python 3-Stil-Print-Funktion in einigen Teilen der Datei verwenden, während andere Teile der Datei immer noch die print-Anweisung verwenden. In Python 2.6-2.7 können Sie die Python 3 print-Funktion erhalten mit:

import __builtin__

print3 = __builtin__.__dict__['print']

Das from __future__ import print_function importiert tatsächlich die print-Funktion nirgendwo in Python 2 - stattdessen deaktiviert es lediglich die Parsing-Regeln für die print-Anweisung im aktuellen Modul, behandelt print wie jeden anderen Variablennamen und erlaubt damit, dass die print-Funktion im builtins-Modul aufgerufen wird.

0 Stimmen

Freut mich endlich eine Antwort zu sehen, die den speziellen Klassenbereich body erwähnt, der nicht durch die ziemlich bekannte LEGB-Regel abgedeckt ist.

28voto

brianray Punkte 1099

Ein etwas vollständigeres Beispiel für den Gültigkeitsbereich:

from __future__ import print_function  # für Unterstützung in Python 2

x = 100
print("1. Global x:", x)
class Test(object):
    y = x
    print("2. Geschlossenes y:", y)
    x = x + 1
    print("3. Geschlossenes x:", x)

    def method(self):
        print("4. Geschlossenes self.x", self.x)
        print("5. Global x", x)
        try:
            print(y)
        except NameError as e:
            print("6.", e)

    def method_local_ref(self):
        try:
            print(x)
        except UnboundLocalError as e:
            print("7.", e)
        x = 200 # verursacht Fehler 7, da der gleiche Name vorhanden ist
        print("8. Lokales x", x)

inst = Test()
inst.method()
inst.method_local_ref()

Ausgabe:

1. Global x: 100
2. Geschlossenes y: 100
3. Geschlossenes x: 101
4. Geschlossenes self.x 101
5. Global x 100
6. globaler Name 'y' ist nicht definiert
7. lokale Variable 'x' wurde vor der Zuweisung referenziert
8. Lokales x 200

6 Stimmen

Dies ist eine großartige Antwort. Es sollte jedoch darauf hingewiesen werden, dass die Unterschiede zwischen method und method_local_ref hervorgehoben werden sollten. method kann auf die globale Variable zugreifen und sie wie in 5. Global x drucken. Aber method_local_ref kann das nicht, weil sie später eine lokale Variable mit demselben Namen definiert. Sie können dies testen, indem Sie die Zeile x = 200 entfernen und den Unterschied sehen.

0 Stimmen

@brianray: Was ist mit z?

0 Stimmen

@kiril Ich habe eine Notiz darüber hinzugefügt

24voto

Jeremy Cantrell Punkte 24497

Die Geltungsbereichsregeln für Python 2.x wurden bereits in anderen Antworten dargelegt. Das Einzige, was ich hinzufügen würde, ist, dass es in Python 3.0 auch das Konzept eines nicht-lokalen Geltungsbereichs gibt (angezeigt durch das Schlüsselwort 'nonlocal'). Dies ermöglicht es Ihnen, äußere Bereiche direkt zu erreichen, und eröffnet die Möglichkeit, einige clevere Tricks zu machen, einschließlich lexikalischer Verschlüsse (ohne hässliche Hacks, die mutable Objekte beinhalten).

EDIT: Hier ist das PEP mit weiteren Informationen dazu.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X