Warum können Funktionen in Python-Druckvariablen im Umschließungsbereich funktionieren, können sie aber nicht in der Zuordnung verwenden?

Wenn ich den folgenden Code ausführe:

x = 1 class Incr: print(x) x = x + 1 print(x) print(x) 

Es druckt:

 1 2 1 

Okay keine Probleme, das ist genau das, was ich erwartet hatte. Und wenn ich folgendes mache:

 x = 1 class Incr: global x print(x) x = x + 1 print(x) print(x) 

Es druckt:

 1 2 2 

Auch was ich erwartet hatte Keine Probleme da

Nun, wenn ich anfange, eine Inkrementfunktion wie folgt zu machen:

 x = 1 def incr(): print(x) incr() 

Es druckt 1 genau wie ich erwartet hatte. Ich nehme an, es tut dies, weil es nicht finden kann, x in seinem lokalen Bereich, so sucht es seine umschließenden Bereich und findet x dort. Bisher keine Probleme.

Nun, wenn ich es tue:

 x = 1 def incr(): print(x) x = x + 1 incr() 

Dies gibt mir den folgenden Fehler in der Rückverfolgung:

UnboundLocalError: lokale Variable 'x' referenziert vor der Zuweisung.

Warum sucht Python nicht nur den umschließenden Raum für x wenn er keinen Wert von x finden kann, der für die Zuweisung verwendet wird, wie meine class Incr ? Beachten Sie, dass ich nicht frage, wie diese Funktion funktionieren Ich weiß, die Funktion wird funktionieren, wenn ich folgendes mache:

 x = 1 def incr(): global x print(x) x = x + 1 print(x) incr() 

Dies wird korrekt drucken:

 1 2 

So wie ich es erwarte Alles, was ich frage ist, warum es nicht nur zieht x aus dem umschließenden Bereich, wenn das Keyword global nicht vorhanden ist, genau wie es für meine Klasse oben getan hat. Warum hat der Dolmetscher die Notwendigkeit, dies als UnboundLocalError zu melden, wenn es klar ist, dass es etwas x gibt. Da die Funktion den Wert bei x zum Drucken lesen konnte, weiß ich, dass es x als Teil des umschließenden Umfangs hat … also warum funktioniert das nicht wie das Klassenbeispiel?

Warum ist der Wert von x für den Druck so unterschiedlich von der Verwendung seines Wertes für die Zuweisung? Ich verstehe es einfach nicht.

7 Solutions collect form web for “Warum können Funktionen in Python-Druckvariablen im Umschließungsbereich funktionieren, können sie aber nicht in der Zuordnung verwenden?”

Klassen und Funktionen sind unterschiedlich, Variablen innerhalb einer Klasse sind eigentlich tatsächlich dem Namespace der Klasse als Attribute zugeordnet, während innerhalb einer Funktion die Variablen nur normale Variablen sind, auf die nicht zugegriffen werden kann.

Die lokalen Variablen innerhalb einer Funktion sind eigentlich entschieden, wenn die Funktion zum ersten Mal analysiert wird, und python wird nicht im globalen Bereich nach ihnen suchen, weil es weiß, dass du es als lokale Variable deklariert hast.

Also, sobald Python sieht ein x = x + 1 (Zuweisung) und es gibt keine global deklariert für diese Variable dann python wird nicht für diese Variable in globalen oder anderen Bereichen suchen.

 >>> x = 'outer' >>> def func(): ... x = 'inner' #x is a local variable now ... print x ... >>> func() inner 

Gemeinsame gotcha:

 >>> x = 'outer' >>> def func(): ... print x #this won't access the global `x` ... x = 'inner' #`x` is a local variable ... print x ... >>> func() ... UnboundLocalError: local variable 'x' referenced before assignment 

Aber wenn Sie eine global Aussage verwenden, dann python für diese Variable im global Bereich zu suchen.

Lesen: Warum bekomme ich einen UnboundLocalError, wenn die Variable einen Wert hat?

nonlocal : Für verschachtelte Funktionen können Sie die nonlocal Anweisung in py3.x verwenden, um eine Variable zu ändern, die in einer umschließenden Funktion deklariert ist.


Aber Klassen arbeiten anders, eine Variable x deklariert innerhalb einer Klasse A tatsächlich wird Ax :

 >>> x = 'outer' >>> class A: ... x += 'inside' #use the value of global `x` to create a new attribute `Ax` ... print x #prints `Ax` ... outerinside >>> print x outer 

Sie können auch auf die Klassenattribute direkt aus dem globalen Geltungsbereich zugreifen:

 >>> Ax 'outerinside' 

Mit global in der Klasse:

 >>> x = 'outer' >>> class A: ... global x ... x += 'inner' #now x is not a class attribute, you just modified the global x ... print x ... outerinner >>> x 'outerinner' >>> Ax AttributeError: class A has no attribute 'x' 

Die Funktion der Grammatik wird keinen Fehler in Klassen erheben:

 >>> x = 'outer' >>> class A: ... print x #fetch from globals or builitns ... x = 'I am a class attribute' #declare a class attribute ... print x #print class attribute, ie `Ax` ... outer I am a class attribute >>> x 'outer' >>> Ax 'I am a class attribute' 

LEGB- Regel: Wenn kein global und nonlocal verwendet wird, sucht python in dieser Reihenfolge.

 >>> outer = 'global' >>> def func(): enclosing = 'enclosing' def inner(): inner = 'inner' print inner #fetch from (L)ocal scope print enclosing #fetch from (E)nclosing scope print outer #fetch from (G)lobal scope print any #fetch from (B)uilt-ins inner() ... >>> func() inner enclosing global <built-in function any> 

Von Python- Scopes und Namespaces:

Es ist wichtig zu erkennen, dass die Bereiche in Textform bestimmt werden: Der globale Geltungsbereich einer in einem Modul definierten Funktion ist der Namensraum des Moduls, egal von wo oder von welcher Alias ​​die Funktion aufgerufen wird. Auf der anderen Seite wird die eigentliche Suche nach Namen dynamisch zur Laufzeit durchgeführt – aber die Sprachdefinition entwickelt sich zur statischen Namensauflösung, bei der "Kompilierzeit", also nicht auf die dynamische Namensauflösung! (In der Tat sind lokale Variablen bereits statisch bestimmt.)

Was bedeutet, dass der Bereich für x = x + 1 statisch bestimmt wird, bevor die Funktion aufgerufen wird. Und da dies eine Aufgabe ist, dann wird 'x' eine lokale Variable und wird nicht global nachgeschlagen.

Das ist auch der Grund, warum from mod import * in Funktionen nicht zugelassen ist. Weil der Dolmetscher keine Module für Sie in Kompilierzeit importiert, um die Namen zu kennen, die Sie in der Funktion verwenden. Dh es muss alle Namen kennen, die in der Funktion zur Kompilierzeit referenziert werden.

Es ist die Regel Python folgt – gewöhnen Sie sich daran 😉 Es gibt einen praktischen Grund: Sowohl der Compiler als auch die menschlichen Leser können bestimmen, welche Variablen lokal sind, indem sie nur auf die Funktion schauen. Welche Namen sind lokal hat nichts mit dem Kontext zu tun, in dem eine Funktion erscheint, und es ist in der Regel eine sehr gute Idee, Regeln zu befolgen, die die Menge an Quellcode beschränken, die Sie anstarren müssen, um eine Frage zu beantworten.

Über:

Ich nehme an, es tut dies, weil es nicht finden kann, x in seinem lokalen Bereich, so sucht es seine umschließenden Umfang und findet x.

Nicht ganz: Der Compiler bestimmt zum Zeitpunkt der Kompilierung, welche Namen sind und nicht lokal sind. Es gibt keine dynamische "hmm – ist das lokal oder global?" Die Suche läuft zur Laufzeit. Die genauen Regeln sind hier beschrieben .

Wenn du nicht brauchst, einen Namen global zu erklären, um nur auf seinen Wert zu verweisen, mag ich Fredrik Lundhs alte Antwort hier . In der Praxis ist es in der Tat wertvoll, dass eine global Aussage Code-Leser darauf hinweist, dass eine Funktion einen globalen Namen rebinden kann.

Weil es so ist, dass es funktionierte.

Grundsätzlich, wenn Sie eine Zuordnung irgendwo in Ihrer Funktion haben, dann wird diese Variable lokal zu dieser Funktion (es sei denn, Sie haben global , natürlich).

Weil es zu sehr schwer führen würde, Bugs zu verfolgen!

Wenn du das x = x + 1 tippest, hättest du ein x in den umschließenden Bereich einschalten können … oder du hättest einfach vergessen lassen können, dass du schon x irgendwo anders benutzt hast und versucht hast, eine lokale Variable zu deklarieren.

Ich würde es vorziehen, dass der Dolmetscher Ihnen erlaubt, den übergeordneten Namensraum zu ändern, wenn Sie beabsichtigen – auf diese Weise können Sie es nicht zufällig machen.

Ich kann versuchen, eine gebildete Vermutung zu machen, warum es so funktioniert.

Wenn Python einen String x = x + 1 in deiner Funktion begegnet, muss er entscheiden, wo man den x nachschlagen soll.

Es könnte sagen, "das erste Vorkommen von x ist global, und das zweite ist lokal", aber das ist ganz zweideutig (und damit gegen die Python-Philosophie). Dies könnte Teil der Syntax werden, aber es führt möglicherweise zu kniffligen Bugs. Deshalb wurde beschlossen, darüber konsistent zu sein und alle Vorkommnisse als globale oder lokale Variablen zu behandeln.

Es gibt eine Zuordnung, also wenn x global sein sollte, würde es eine global Aussage geben, aber keiner wird gefunden.

Daher ist x lokal, aber es ist nicht an irgendetwas gebunden, und doch wird es im Ausdruck x + 1 . UnboundLocalError .

Als zusätzliches Beispiel für die neu erstellte Axt, die in der Klasse erstellt wurde. Die Neuzuordnung von x zu 'innerem' innerhalb der Klasse aktualisiert den globalen Wert von x nicht, da es nun eine Klassenvariable ist.

 x = 'outer' class A: x = x print(x) x = 'inner' print(x) print(x) print(Ax) 
  • Variabler Bereich (Python Newbie)
  • Wie kann man neue Scopes in Python schaffen?
  • Globals und Einheimische in python exec ()
  • Kurze Beschreibung der Scoping Regeln?
  • Was bedeutet Umfang
  • Funktion Ortsname Bindung aus einem äußeren Bereich
  • Python: Variablen sind noch zugänglich, wenn in try oder if definiert?
  • Python Variable Scope (Vorbehalt durch Verweis oder Kopie?)
  • UnboundLocalError bei der Manipulation von Variablen ergibt inkonsistentes Verhalten
  • Python eval (kompilieren (...), Sandkasten), Globals gehen in Sandbox, wenn nicht in def, warum?
  • Lambda-Funktion acessing außerhalb variabel [duplicate]
  • Python ist die beste Programmiersprache der Welt.