Was genau sind die Python-Scoping-Regeln?
Wenn ich Code habe:
code1
class Foo:
code2
def spam.....
code3
for code4..:
code5
x()
Wo ist zu x
finden? Einige mögliche Optionen sind die folgende Liste:
- In der beiliegenden Quelldatei
- Im Klassennamensraum
- In der Funktionsdefinition
- In der for-Schleifenindexvariablen
- Innerhalb 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 laufen Lambda-Funktionen etwas anders?
Es muss irgendwo eine einfache Referenz oder einen Algorithmus geben. Es ist eine verwirrende Welt für fortgeschrittene Python-Programmierer.
python
scope
dynamic-languages
Charles Merriam
quelle
quelle
Antworten:
Eigentlich eine prägnante Regel für die Auflösung von Python Scope aus Learning Python, 3 .. Ed. . (Diese Regeln gelten nur für Variablennamen und nicht für Attribute. Wenn Sie ohne Punkt darauf verweisen, gelten diese Regeln.)
LEGB-Regel
L Ocal - Namen innerhalb einer Funktion in irgendeiner Weise zugeordnet (
def
oderlambda
), und nicht deklarierte globale in dieser FunktionE nclosing-Funktion - Namen, die im lokalen Bereich aller statisch einschließenden Funktionen (
def
oderlambda
) von innen nach außen zugewiesen werdenG lobal (Modul) - Namen auf der obersten Ebene einer Moduldatei zugeordnet ist , oder durch eine Ausführung von
global
Anweisung in einemdef
innerhalb der DateiB uilt-in (Python) - Namen vorbelegt im eingebauten Namen Modul:
open
,range
,SyntaxError
, usw.Also im Fall von
Die
for
Schleife hat keinen eigenen Namespace. In der LEGB-Reihenfolge wären die Bereichedef spam
(incode3
,code4
undcode5
)def
)x
im Modul (incode1
) global deklariert ?x
in Python eingebauten .x
wird niemals in gefunden werdencode2
(selbst in Fällen, in denen Sie dies erwarten könnten, siehe Anttis Antwort oder hier ).quelle
global(var_name)
syntaktisch falsch. Die korrekte Syntax wäreglobal var_name
ohne Klammern. Sie haben jedoch einen gültigen Punkt.>>> def foo(x): ... y = x ... def bar(z): ... y = z ... bar(5) ... print x,y ... >>> foo(3) 3 3
y
geschrieben wird und es keineglobal y
Erklärungen gibt - siehe @ Peters Kommentar.Im Wesentlichen ist das einzige, was in Python einen neuen Bereich einführt, eine Funktionsdefinition. Klassen sind insofern ein Sonderfall, als alles, was direkt im Body definiert ist, im Namespace der Klasse platziert wird, aber nicht direkt über die darin enthaltenen Methoden (oder verschachtelten Klassen) zugänglich ist.
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 Bereich - enthält alles, was in Code1 definiert ist, sowie Foo (und was sich danach ändert)
Der eingebaute Namespace. Ein Sonderfall - dieser enthält die verschiedenen in Python integrierten Funktionen und Typen wie len () und str (). Im Allgemeinen sollte dies nicht durch einen Benutzercode geändert werden. Erwarten Sie daher, dass dieser die Standardfunktionen und nichts anderes enthält.
Weitere Bereiche werden nur angezeigt, wenn Sie eine verschachtelte Funktion (oder Lambda) in das Bild einfügen. Diese verhalten sich jedoch 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.
Beschränkungen:
Auf Variablen in anderen Bereichen als den Variablen der lokalen Funktion kann zugegriffen werden, sie können jedoch nicht ohne weitere Syntax auf neue Parameter zurückgesetzt werden. Stattdessen wird durch die Zuweisung eine neue lokale Variable erstellt, anstatt die Variable im übergeordneten Bereich zu beeinflussen. Zum Beispiel:
Um die Bindungen globaler Variablen innerhalb eines Funktionsbereichs tatsächlich zu ändern, müssen Sie angeben, dass die Variable mit dem globalen Schlüsselwort global ist. Z.B:
Derzeit gibt es keine Möglichkeit, dasselbe für Variablen in eingeschlossenen Funktionsbereichen zu tun. Python 3 führt jedoch ein neues Schlüsselwort ein, "
nonlocal
" das sich ähnlich wie globale, jedoch für verschachtelte Funktionsbereiche verhält.quelle
Es gab keine gründliche Antwort bezüglich der Python3-Zeit, daher habe ich hier eine Antwort gegeben. Das meiste, was hier beschrieben wird, ist in der 4.2.2 Auflösung der Namen der Python 3-Dokumentation beschrieben.
Wie in anderen Antworten angegeben, gibt es 4 grundlegende Bereiche, den LEGB, für Local, Enclosing, Global und Builtin. Zusätzlich zu diesen gibt es einen speziellen Bereich, den Klassenkörper , der keinen umschließenden Bereich für innerhalb der Klasse definierte Methoden umfasst. Durch Zuweisungen innerhalb des Klassenkörpers wird die Variable von da an im Klassenkörper gebunden.
Insbesondere erstellt keine Blockanweisung außer
def
undclass
einen variablen Bereich. In Python 2 erstellt ein Listenverständnis keinen Variablenbereich. In Python 3 wird jedoch die Schleifenvariable innerhalb des Listenverständnisses in einem neuen Bereich erstellt.Die Besonderheiten des Klassenkörpers demonstrieren
Im Gegensatz zum Funktionskörper können Sie die Variable daher im Klassenkörper demselben Namen zuweisen, um eine Klassenvariable mit demselben Namen zu erhalten. Weitere Suchvorgänge für diesen Namen werden stattdessen in die Klassenvariable aufgelöst.
Eine der größeren Überraschungen für viele Python-Neulinge ist, dass eine
for
Schleife keinen variablen Bereich erstellt. In Python 2 erstellen die Listenverständnisse auch keinen Bereich (während Generatoren und Diktverständnisse dies tun!). Stattdessen verlieren sie den Wert in der Funktion oder im globalen Bereich:Das Verständnis kann als gerissene (oder schreckliche, wenn Sie so wollen) Methode verwendet werden, um modifizierbare Variablen in Lambda-Ausdrücken in Python 2 zu erstellen. Ein Lambda-Ausdruck erstellt einen Variablenbereich, wie es die
def
Anweisung tun würde, aber in Lambda sind keine Anweisungen zulässig. Zuweisung als Anweisung in Python bedeutet, dass keine Variablenzuweisungen in Lambda zulässig sind, aber ein Listenverständnis ein Ausdruck ist ...Dieses Verhalten wurde in Python 3 behoben - keine Verständnisausdrücke oder Generatoren lecken Variablen.
Das Globale bedeutet wirklich den Modulumfang; Das Hauptmodul von Python ist das
__main__
; Auf alle importierten Module kann über diesys.modules
Variable zugegriffen werden. um Zugang zu erhalten__main__
, kann man verwendensys.modules['__main__']
, oderimport __main__
; 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 wird (außer im Klassenbereich), wird er als zu diesem Bereich gehörend betrachtet, andernfalls wird er als zu einem umschließenden Bereich gehörend betrachtet, der der Variablen zugewiesen wird (möglicherweise wird er nicht zugewiesen noch oder gar nicht) oder schließlich den globalen Geltungsbereich. Wenn die Variable als lokal betrachtet wird, aber noch nicht festgelegt ist oder gelöscht wurde, führt das Lesen des Variablenwerts zu
UnboundLocalError
einer Unterklasse vonNameError
.Der Bereich kann deklarieren, dass er die globale Variable (Modulbereich) explizit mit dem globalen Schlüsselwort ändern möchte:
Dies ist auch dann möglich, wenn es im umschließenden Bereich beschattet wurde:
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 einer Länge von 1:
In Python 3
nonlocal
kommt das jedoch zur Rettung:Die
nonlocal
Dokumentation sagt dasdh
nonlocal
bezieht sich immer auf den innersten äußeren nicht globalen Bereich, an den der Name gebunden wurde (dh zugewiesen, einschließlich alsfor
Zielvariable, in derwith
Klausel oder als Funktionsparameter verwendet).Jede Variable, die nicht als lokal für den aktuellen Bereich oder einen umschließenden Bereich angesehen wird, ist eine globale Variable. Ein globaler Name wird im globalen Wörterbuch des Moduls nachgeschlagen. Wenn es nicht gefunden wird, 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 jetztbuiltins
. Wenn Sie einem Attribut des eingebauten Moduls zuweisen, wird es anschließend für jedes Modul als lesbare globale Variable angezeigt, es sei denn, dieses Modul schattiert 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 verwenden, in anderen Teilen der Datei wird die
print
Anweisung jedoch weiterhin verwendet . In Python 2.6-2.7 können Sie die Python 3-print
Funktion mit folgenden Funktionen abrufen :Das
from __future__ import print_function
importiert dieprint
Funktion eigentlich nirgendwo in Python 2 - stattdessen deaktiviert es nur die Parsing-Regeln fürprint
Anweisungen im aktuellen Modul, behandelt sieprint
wie jede andere Variablenkennung und ermöglicht soprint
das Nachschlagen der Funktion in den integrierten Funktionen.quelle
Die Gültigkeitsbereichsregeln für Python 2.x wurden bereits in anderen Antworten beschrieben. Das einzige, was ich hinzufügen möchte, ist, dass es in Python 3.0 auch das Konzept eines nicht lokalen Bereichs gibt (angezeigt durch das Schlüsselwort 'nonlocal'). Auf diese Weise können Sie direkt auf äußere Bereiche zugreifen und einige nützliche Tricks ausführen, einschließlich lexikalischer Verschlüsse (ohne hässliche Hacks mit veränderlichen Objekten).
EDIT: Hier ist der PEP mit mehr Informationen dazu.
quelle
Ein etwas vollständigeres Beispiel für den Umfang:
Ausgabe:
quelle
method
und hervorgehoben werdenmethod_local_ref
sollten.method
kann auf die globale Variable zugreifen und sie wie in drucken5. Global x
. Abermethod_local_ref
kann nicht , weil später definiert sie eine lokale Variable mit dem gleichen Namen. Sie können dies testen, indem Sie diex = 200
Linie entfernen und den Unterschied sehenPython löst Ihre Variablen mit - im Allgemeinen - drei verfügbaren Namespaces auf.
Es gibt zwei Funktionen:
globals
undlocals
die Ihnen den Inhalt von zwei 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 Hauptteil der Methodenfunktion
Foo.spam
.Global ist - na ja - global.
Die Regel besteht darin, die verschachtelten lokalen Bereiche zu durchsuchen, die durch Methodenfunktionen (und verschachtelte Funktionsdefinitionen) erstellt wurden, und dann global zu suchen. Das ist es.
Es gibt keine anderen Bereiche. Die
for
Anweisung (und andere zusammengesetzte Anweisungen wieif
undtry
) erstellen keine neuen verschachtelten Bereiche. Nur Definitionen (Pakete, Module, Funktionen, Klassen und Objektinstanzen.)Innerhalb einer Klassendefinition sind die Namen Teil des Klassennamensraums.
code2
muss beispielsweise durch den Klassennamen qualifiziert sein. Im AllgemeinenFoo.code2
. Jedoch,self.code2
auch, da Python-Objekte die enthaltende Klasse als Ersatz betrachten.Ein Objekt (eine Instanz einer Klasse) hat Instanzvariablen. Diese Namen befinden sich im Namespace des Objekts. Sie müssen vom Objekt qualifiziert werden. (
variable.instance
.)Innerhalb einer Klassenmethode haben Sie Einheimische und Globale. Sie sagen
self.variable
, Sie sollen die Instanz als Namespace auswählen. Das wirst du bemerkenself
ein Argument für jede Klassenmitgliedsfunktion ist und sie Teil des lokalen Namespace macht.Siehe Python-Bereichsregeln , Python-Bereich , Variabler Bereich .
quelle
Python has two namespaces available. Global and local-to-something.
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) ist für Code innerhalb von Methoden derselben Klasse nicht sichtbar. Normalerweise greifen Sie mit self auf sie zu. Code4 / Code5 (Schleifen) befinden sich im selben Bereich wie Code3. Wenn Sie also dort in 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 Globals in dem Modul, aus dem es stammt (definiert in Code1), und auf alle anderen enthaltenen Bereiche (siehe unten). Auf Code2-Mitglieder würde wieder über self zugegriffen.
Lambda ist nicht anders als def. Wenn in einer Funktion ein Lambda verwendet wird, entspricht dies dem Definieren 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 übernimmt die innerste Instanz:
fun3 sieht die Instanz x aus dem nächsten enthaltenden Bereich, der dem mit fun2 zugeordneten Funktionsbereich 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, sofern Sie nicht ausdrücklich mit einem From-Future-Import nach der Funktion fragen - sind die Bereiche von fun1 und fun2 für fun3 nicht sichtbar, sodass die Antwort von S.Lott gilt und Sie das globale x erhalten ::
quelle
In Python
Wenn eine Variable im aktuellen Bereich nicht gefunden werden kann, lesen Sie bitte die LEGB-Reihenfolge.
quelle