Python ist ein wenig seltsam, dass es alles in einem Wörterbuch für die verschiedenen Bereiche hält. Die ursprünglichen a,b,c befinden sich im obersten Bereich und damit in diesem obersten Wörterbuch. Die Funktion hat ihr eigenes Wörterbuch. Wenn Sie den print(a)
y print(b)
Anweisungen gibt es nichts mit diesem Namen im Wörterbuch, also schaut Python in der Liste nach und findet sie im globalen Wörterbuch.
Jetzt kommen wir zu c+=1
, was natürlich gleichbedeutend ist mit c=c+1
. Wenn Python diese Zeile durchsucht, sagt es: "Aha, es gibt eine Variable mit dem Namen c, ich werde sie in mein lokales Wörterbuch aufnehmen." Wenn es dann nach einem Wert für c für das c auf der rechten Seite der Zuweisung sucht, findet es seinen lokale Variable namens c die noch keinen Wert hat und daher den Fehler auslöst.
Die Erklärung global c
sagt dem Parser einfach, dass er die c
aus dem globalen Bereich und benötigt daher keinen neuen.
Der Grund, warum es sagt, es gibt ein Problem in der Zeile, die es tut, ist, weil es effektiv für die Namen suchen, bevor es versucht, Code zu generieren, und so in gewissem Sinne nicht denken, es ist wirklich tun, dass Zeile noch. Ich würde argumentieren, dass dies ein Fehler in der Benutzerfreundlichkeit ist, aber es ist im Allgemeinen eine gute Praxis, einfach zu lernen, die Meldungen eines Compilers nicht zu beachten zu ernsthaft.
Falls es Sie tröstet, ich habe wahrscheinlich einen ganzen Tag mit demselben Thema verbracht, bevor ich etwas fand, das Guido über die Wörterbücher, die alles erklären, geschrieben hatte.
Update, siehe Kommentare:
Der Code wird nicht zweimal gescannt, sondern in zwei Phasen: Lexing und Parsing.
Betrachten Sie, wie das Parsen dieser Codezeile funktioniert. Der Lexer liest den Quelltext und zerlegt ihn in Lexeme, die "kleinsten Bestandteile" der Grammatik. Wenn er also auf die Zeile
c+=1
zerfällt es in etwas wie
SYMBOL(c) OPERATOR(+=) DIGIT(1)
Der Parser will daraus schließlich einen Parse-Baum machen und ihn ausführen, aber da es sich um eine Zuweisung handelt, sucht er vorher nach dem Namen c im lokalen Wörterbuch, findet ihn nicht und fügt ihn in das Wörterbuch ein und markiert ihn als nicht initialisiert. In einer vollständig kompilierten Sprache würde er einfach in die Symboltabelle gehen und auf das Parsen warten, aber da er nicht den Luxus eines zweiten Durchgangs hat, macht der Lexer ein wenig zusätzliche Arbeit, um das Leben später einfacher zu machen. Nur, dann sieht er den OPERATOR, sieht, dass die Regeln besagen "wenn du einen Operator += hast, muss die linke Seite initialisiert worden sein" und sagt "Ups!"
Der Punkt ist hier, dass es hat noch nicht wirklich mit der Analyse der Zeile begonnen . Dies alles geschieht sozusagen in Vorbereitung auf das eigentliche Parsen, so dass der Zeilenzähler noch nicht zur nächsten Zeile vorgerückt ist. Wenn er also den Fehler meldet, denkt er immer noch, dass er in der vorherigen Zeile steht.
Wie ich schon sagte, könnte man argumentieren, dass es sich um einen Fehler in der Benutzerfreundlichkeit handelt, aber eigentlich ist es eine ziemlich häufige Sache. Einige Compiler sind da ehrlicher und sagen "Fehler in oder um Zeile XXX", aber dieser nicht.
0 Stimmen
Ist damit Ihre Frage beantwortet? Ich verstehe nicht, warum UnboundLocalError auftritt (Schließung)
1 Stimmen
Gleicher Fehler, aber andere Ursache: "UnboundLocalError: lokale Variable vor Zuweisung referenziert" nach einer if-Anweisung