it-swarm.com.de

Kurze Beschreibung der Scoping-Regeln?

Welche genau sind die Python Scoping-Regeln?

Wenn ich Code habe:

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

Wo wird x gefunden? Zu den möglichen Optionen gehört die folgende Liste:

  1. In der beiliegenden Quelldatei
  2. Im Klassennamensraum
  3. In der Funktionsdefinition
  4. In der for-Schleifenindexvariablen
  5. In der for-Schleife

Es gibt auch den Kontext während der Ausführung, wenn die Funktion spam an eine andere Stelle übergeben wird. Und vielleicht Lambda-Funktionen etwas anders übergeben?

Irgendwo muss es eine einfache Referenz oder einen Algorithmus geben. Es ist eine verwirrende Welt für fortgeschrittene Python Programmierer.

446
Charles Merriam

Eigentlich eine prägnante Regel für Python Scope resolution, from Learning Python, 3rd. Ed. . (Diese Regeln gelten nur für Variablennamen, nicht für Attribute. Wenn Sie darauf verweisen Ohne Punkt gelten diese Regeln.)

LEGB-Regel

  • [~ # ~] l [~ # ~] ocal - Namen, die in einer Funktion (def oder lambda) und in dieser Funktion nicht als global deklariert

  • [~ # ~] e [~ # ~] nclosing-function - Namen, die im lokalen Bereich aller statisch einschließenden Funktionen vergeben werden (def oder lambda), von innen nach außen

  • [~ # ~] g [~ # ~] lobal (Modul) - Namen, die auf der obersten Ebene einer Moduldatei oder durch Ausführen von a zugewiesen werden global Anweisung in einem def innerhalb der Datei

  • [~ # ~] b [~ # ~] uilt-in (Python) - Namen, die im integrierten Namensmodul vorab zugewiesen wurden: 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 ganze Beispiel in einem anderen def wäre)
  • G: Wurde im Modul x global deklariert (in code1)?
  • B: Beliebiges in Python eingebautes x.

x wird niemals in code2 gefunden (auch in Fällen, in denen Sie dies erwarten könnten, siehe Anttis Antwort oder hier ).

399
Rizwan Kassim

Im Grunde ist das einzige, was in Python einen neuen Gültigkeitsbereich einführt, eine Funktionsdefinition. Klassen sind insofern ein Sonderfall, als alles, was direkt im Hauptteil definiert ist, in den Namensraum der Klasse gestellt wird, aber Sie sind in den darin enthaltenen Methoden (oder verschachtelten Klassen) nicht direkt zugänglich.

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

  • spam-Bereich - enthält alles, was in Code3 und Code5 definiert ist (sowie Code4, Ihre Schleifenvariable)

  • Der globale Geltungsbereich - enthält alles, was in Code1 definiert ist, sowie Foo (und was sich danach ändert)

  • Der eingebaute Namespace. Ein kleiner Sonderfall - dies enthält die verschiedenen Python eingebauten Funktionen und Typen wie len () und str (). Im Allgemeinen sollte dies durch keinen Benutzercode geändert werden. Erwarten Sie es also die Standardfunktionen und sonst nichts zu enthalten.

Weitere Bereiche werden nur angezeigt, wenn Sie eine verschachtelte Funktion (oder Lambda) in das Bild einfügen. Diese verhalten sich jedoch so ziemlich so, wie Sie es erwarten würden. Die verschachtelte Funktion kann auf alles im lokalen Bereich sowie auf alles im Bereich der umschließenden Funktion zugreifen. z.B.

def foo():
    x=4
    def bar():
        print x  # Accesses x from foo's scope
    bar()  # Prints 4
    x=5
    bar()  # Prints 5

Einschränkungen:

Auf Variablen in anderen Bereichen als den Variablen der lokalen Funktion kann zugegriffen werden, sie können jedoch nicht ohne weitere Syntax an neue Parameter gebunden werden. Stattdessen wird durch die Zuweisung eine neue lokale Variable erstellt, anstatt die Variable im übergeordneten Bereich zu beeinflussen. Zum Beispiel:

global_var1 = []
global_var2 = 1

def func():
    # This is OK: It's just accessing, not rebinding
    global_var1.append(4) 

    # This won't affect global_var2. Instead it creates a new variable
    global_var2 = 2 

    local1 = 4
    def embedded_func():
        # Again, this doen't affect func's local1 variable.  It creates a 
        # new local variable also called local1 instead.
        local1 = 5
        print local1

    embedded_func() # Prints 5
    print local1    # Prints 4

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

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

Derzeit gibt es keine Möglichkeit, das Gleiche für Variablen beim Einschließen von Funktionsbereichen zu tun, aber Python 3 führt ein neues Schlüsselwort ein , "nonlocal", das sich ähnlich wie global verhält, jedoch für verschachtelte Funktionsbereiche.

148
Brian

Es gab keine gründliche Antwort bezüglich der Python3-Zeit, daher habe ich hier eine Antwort gegeben.

Wie in anderen Antworten angegeben, gibt es vier grundlegende Bereiche: LEGB für Local, Enclosing, Global und Builtin. Darüber hinaus gibt es einen speziellen Gültigkeitsbereich, den Klassenhauptteil, der keinen einschließenden Gültigkeitsbereich für in der Klasse definierte Methoden enthält. Zuweisungen innerhalb des Klassenkörpers bewirken, dass die Variable von da an im Klassenkörper gebunden wird.

Insbesondere erstellen no Blockanweisung neben def und class einen Variablenbereich. In Python 2 erstellt ein Listenverständnis keinen Variablenbereich, in Python 3 wird die Schleifenvariable innerhalb des Listenverständnisses jedoch in einem neuen Bereich erstellt.

Die Besonderheiten des Klassenkörpers demonstrieren

x = 0
class X(object):
    y = x
    x = x + 1 # x is now a variable
    z = x

    def method(self):
        print(self.x) # -> 1
        print(x)      # -> 0, the global x
        print(y)      # -> NameError: global name 'y' is not defined

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

Anders als in function body können Sie daher die Variable im class body demselben Namen zuweisen, um eine Klassenvariable mit demselben Namen zu erhalten. Weitere Suchen nach diesem Namen werden stattdessen in die Klassenvariable aufgelöst.


Eine der größten Überraschungen für viele Neulinge in Python ist, dass eine for - Schleife keinen variablen Bereich erstellt. In Python 2 erstellen die Listenverständnisse auch keinen Gültigkeitsbereich (während dies bei Generatoren und Diktierverständnissen der Fall ist!). Stattdessen verlieren sie den Wert in der Funktion oder im globalen Gültigkeitsbereich:

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

Das Verständnis kann als listige (oder schreckliche) Methode verwendet werden, um modifizierbare Variablen in Lambda-Ausdrücken in Python 2 zu erstellen. Ein Lambda-Ausdruck erstellt einen Variablenbereich wie def. aussage würde, aber innerhalb von lambda sind keine aussagen erlaubt. Zuweisung als Anweisung in Python bedeutet, dass keine Variablenzuweisungen in Lambda zulässig sind, aber ein Listenverständnis ist ein Ausdruck ...

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


Das Globale bedeutet wirklich den Modulumfang; das Hauptmodul python ist der __main__; Alle importierten Module sind über die Variable sys.modules zugänglich. um Zugriff auf __main__ zu erhalten, kann man sys.modules['__main__'] oder import __main__ verwenden; Es ist durchaus akzeptabel, dort auf Attribute zuzugreifen und diese zuzuweisen. Sie werden als Variablen im globalen Bereich des Hauptmoduls angezeigt.


Wenn ein Name jemals im aktuellen Bereich zugewiesen wurde (außer im Klassenbereich), wird er als zu diesem Bereich gehörig angesehen, andernfalls wird er als zu einem umschließenden Bereich gehörig angesehen, der der Variablen zugewiesen wurde (er wird möglicherweise nicht zugewiesen) noch oder gar nicht) oder endlich den globalen Geltungsbereich. Wenn die Variable als lokal betrachtet wird, aber noch nicht festgelegt oder gelöscht wurde, führt das Lesen des Variablenwerts zu UnboundLocalError, einer Unterklasse von NameError.

x = 5
def foobar():
    print(x)  # causes UnboundLocalError!
    x += 1    # because assignment here makes x a local variable within the function

# call the function
foobar()

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

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

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

Dies ist auch dann möglich, wenn es in einem umschließenden Bereich beschattet wurde:

x = 5
y = 13
def make_closure():
    x = 42
    y = 911
    def func():
        global x # sees the global value
        print(x, y)
        x += 1

    return func

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

In python 2 gibt es keine einfache Möglichkeit, den Wert im umschließenden Bereich zu ändern. In der Regel wird dies durch einen veränderlichen Wert simuliert, z. B. eine Liste mit der Länge 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 die 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() # identical behavior to the previous example.

Jede Variable, die nicht als lokal für den aktuellen Bereich oder einen umschließenden Bereich gilt, ist eine globale Variable. Ein globaler Name wird im globalen Wörterbuch des Moduls nachgeschlagen. Wird es nicht gefunden, wird das Global vom eingebauten Modul nachgeschlagen. Der Name des Moduls wurde von python 2 in python 3 geändert. in python 2 war es __builtin__ und in python 3 heißt es jetzt builtins. Wenn Sie ein Attribut des eingebauten Moduls zuweisen, wird es danach für jedes Modul als lesbare globale Variable angezeigt, es sei denn, das Modul spiegelt sie mit einer eigenen globalen Variablen mit demselben Namen.


Das Lesen des eingebauten Moduls kann ebenfalls nützlich sein. Angenommen, Sie möchten die Druckfunktion im python 3-Stil in einigen Teilen der Datei, in anderen Teilen der Datei wird jedoch weiterhin die Anweisung print verwendet. In Python 2.6-2.7 können Sie die Funktion Python 3 print aufrufen mit:

import __builtin__

print3 = __builtin__.__dict__['print']

Die Funktion from __future__ import print_function Importiert die Funktion print nicht irgendwo in Python 2 - stattdessen werden nur die Analyseregeln für die Anweisung print im aktuellen Modul deaktiviert. Behandeln Sie print wie jeden anderen Variablenbezeichner und lassen Sie so die print - Funktion in den Builtins nachschlagen.

105
Antti Haapala

Die Scoping - Regeln für Python 2.x wurden bereits in anderen Antworten umrissen. Das einzige, was ich hinzufügen möchte, ist, dass es in Python 3.0 auch das gibt Konzept eines nicht lokalen Gültigkeitsbereichs (gekennzeichnet durch das Schlüsselwort 'nonlocal'): Auf diese Weise können Sie direkt auf äußere Gültigkeitsbereiche zugreifen und einige nützliche Tricks ausführen, einschließlich lexikalischer Abschlüsse (ohne hässliche Hacks mit veränderlichen Objekten).

EDIT: Hier ist das PEP mit weiteren Informationen dazu.

21
Jeremy Cantrell

Ein etwas vollständigeres Beispiel für den Geltungsbereich:

from __future__ import print_function  # for python 2 support

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

    def method(self):
        print("4. Enclosed 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 # causing 7 because has same name
        print("8. Local x", x)

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

ausgabe:

1. Global x: 100
2. Enclosed y: 100
3. Enclosed x: 101
4. Enclosed self.x 101
5. Global x 100
6. global name 'y' is not defined
7. local variable 'x' referenced before assignment
8. Local x 200
20
brianray

In Python werden Ihre Variablen mit im Allgemeinen drei verfügbaren Namespaces aufgelöst.

Zu jeder Zeit während der Ausführung gibt es mindestens drei verschachtelte Bereiche, auf deren Namespaces direkt zugegriffen werden kann: Der innerste Bereich, der zuerst durchsucht wird, enthält die lokalen Namen; die Namespaces aller umschließenden Funktionen, die ab dem nächstgelegenen umschließenden Gültigkeitsbereich durchsucht werden; Der mittlere Bereich, der als nächstes durchsucht wird, enthält die globalen Namen des aktuellen Moduls. und der äußerste Bereich (zuletzt gesucht) ist der Namespace, der integrierte Namen enthält.

Es gibt zwei Funktionen: globals und locals, die Ihnen den Inhalt zweier dieser Namespaces anzeigen.

Namespaces werden durch Pakete, Module, Klassen, Objektkonstruktionen und Funktionen erstellt. Es gibt keine anderen Arten von Namespaces.

In diesem Fall muss der Aufruf einer Funktion mit dem Namen x im lokalen Namensraum oder im globalen Namensraum aufgelöst werden.

Lokal ist in diesem Fall der Body der Methodenfunktion Foo.spam.

Global ist - na ja - global.

Die Regel besteht darin, die verschachtelten lokalen Bereiche zu durchsuchen, die von Methodenfunktionen (und Definitionen verschachtelter Funktionen) erstellt wurden, und anschließend global zu suchen. Das ist es.

Es gibt keine anderen Bereiche. Die Anweisung for (und andere zusammengesetzte Anweisungen wie if und try) erstellen keine neuen verschachtelten Bereiche. Nur Definitionen (Pakete, Module, Funktionen, Klassen und Objektinstanzen.)

Innerhalb einer Klassendefinition sind die Namen Teil des Klassennamensraums. code2 muss zum Beispiel durch den Klassennamen qualifiziert sein. Allgemein Foo.code2. Jedoch, self.code2 funktioniert auch, weil Python Objekte die enthaltende Klasse als Fallback betrachten.

Ein Objekt (eine Instanz einer Klasse) hat Instanzvariablen. Diese Namen befinden sich im Namespace des Objekts. Sie müssen vom Objekt qualifiziert sein. (variable.instance.)

Innerhalb einer Klassenmethode haben Sie Einheimische und Globale. Du sagst self.variable, um die Instanz als Namespace auszuwählen. Sie werden feststellen, dass self ein Argument für jede Klassenmitgliedsfunktion ist und es Teil des lokalen Namespaces macht.

Siehe Python-Scope-Regeln , Python-Scope , Variablen-Scope .

11
S.Lott

Wo ist x gefunden?

x wird nicht gefunden, da Sie es nicht definiert haben. :-) Es könnte in Code1 (global) oder Code3 (lokal) gefunden werden, wenn Sie es dort ablegen.

code2 (Klassenmitglieder) sind für Code in Methoden derselben Klasse nicht sichtbar - normalerweise greifen Sie mit self darauf zu. code4/code5 (Schleifen) befinden sich im selben Gültigkeitsbereich wie code3. Wenn Sie also dort an x ​​schreiben, ändern Sie die in code3 definierte x-Instanz und erstellen kein neues x.

Python hat einen statischen Gültigkeitsbereich. Wenn Sie also Spam an eine andere Funktion übergeben, hat Spam weiterhin Zugriff auf globale Elemente in dem Modul, von dem es stammt (definiert in Code1), und auf alle anderen Gültigkeitsbereiche (siehe unten). Auf code2-Mitglieder würde wiederum über self zugegriffen werden.

lambda ist nicht anders zu def. Wenn in einer Funktion ein Lambda verwendet wird, entspricht dies der Definition einer verschachtelten Funktion. Ab Python 2.2 sind verschachtelte Bereiche verfügbar. In diesem Fall können Sie x auf jeder Ebene der Funktionsverschachtelung binden und Python nimmt die innerste Instanz auf:

x= 0
def fun1():
    x= 1
    def fun2():
        x= 2
        def fun3():
            return x
        return fun3()
    return fun2()
print fun1(), x

2 0

fun3 erkennt die Instanz x im nächstgelegenen enthaltenden Bereich, der dem Funktionsbereich von fun2 zugeordnet ist. Die anderen x Instanzen, die in fun1 und global definiert sind, sind jedoch nicht betroffen.

Vor nested_scopes - in Python vor 2.1 und in 2.1, es sei denn, Sie fordern ausdrücklich die Funktion mit einem from-future-Import an - fun1- und fun2-Bereiche sind für fun3 nicht sichtbar, so S.Lott's Antwort hält und Sie würden das globale x erhalten:

0 0
7
bobince

In Python

jede Variable, der ein Wert zugewiesen wurde, ist lokal für den Block, in dem die Zuweisung angezeigt wird.

Wenn eine Variable im aktuellen Bereich nicht gefunden werden kann, beziehen Sie sich bitte auf die LEGB-Bestellung.

0
GraceMeng