Ich habe kürzlich diesen Fall von UnboundLocalError
durchgelaufen, was merkwürdig erscheint:
Was produziert:
%Vor% pprint
ist eindeutig in globals
gebunden und wird in locals
in der folgenden Anweisung gebunden. Kann jemand erklären, warum es nicht glücklich ist, pprint
auf die Bindung in globals
hier aufzulösen?
Bearbeiten: Dank der guten Antworten kann ich meine Frage mit relevanter Terminologie klären:
Zur Kompilierzeit wird die Kennung pprint
als lokal für den Rahmen markiert. Hat das Ausführungsmodell keine Unterscheidung wo innerhalb des Rahmens die lokale Kennung gebunden ist? Kann man sagen: "Beziehen Sie sich auf die globale Bindung bis zu dieser Bytecode-Anweisung, an welcher Stelle es zu einer lokalen Bindung zurückgeworfen wurde", oder berücksichtigt das Ausführungsmodell dies nicht?
Sieht aus, als ob Python die from pprint import pprint
-Zeile sieht und pprint
als lokalen Namen für main()
markiert, bevor irgendeinen Code ausführt. Da Python denkt, dass pprint eine lokale Variable sein sollte, referenziert es mit pprint.pprint()
, bevor es mit der from..import
-Anweisung "zugewiesen" wird, und löst diesen Fehler aus.
Das ist so viel Sinn wie ich das machen kann.
Die Moral besteht natürlich darin, diese import
-Anweisungen immer an die Spitze des Bereichs zu setzen.
Wo ist die Überraschung? Die globale Variable Any für einen Bereich, den Sie innerhalb dieses Bereichs neu zuweisen, wird vom Compiler als lokal für diesen Bereich markiert.
Wenn Importe anders gehandhabt würden, wäre das überraschend imho.
Es kann sinnvoll sein, Module nicht nach den darin verwendeten Symbolen zu benennen oder umgekehrt.
Nun, das war interessant genug für mich, um etwas zu experimentieren und ich lese Ссылка
Dann habe ich hier und da etwas mit deinem Code herumgebastelt, das konnte ich finden:
code:
%Vor%Ausgabe:
%Vor% In der Methode two()
from pprint import pprint
, überschreibt jedoch nicht den Namen pprint
in globals
, da das global
-Schlüsselwort im nicht % two()
verwendet wird.
In der Methode three()
, da es keine Deklaration von pprint
name im lokalen Bereich gibt, wird standardmäßig der globale Name pprint
verwendet, der ein Modul
Während in main()
zuerst das Schlüsselwort global
verwendet wird , beziehen sich alle Verweise auf pprint
im Bereich der Methode main()
auf global
name pprint
. Was wir sehen können, ist zunächst ein Modul und wird in global
namespace
mit einer Methode überschrieben, wie wir from pprint import pprint
Obwohl das vielleicht nicht die Frage als solche beantwortet, aber trotzdem ist es eine interessante Tatsache, denke ich.
======================
Bearbeiten Noch eine interessante Sache.
Wenn Sie ein Modul haben, sagen Sie:
mod1
und eine andere Methode sagen:
mod2
Das scheint auf den ersten Blick korrekt zu sein, da Sie das Modul datetime
in mod2
importiert haben.
Wenn Sie jetzt versuchen, mod2 als Skript auszuführen, wird ein Fehler ausgegeben:
%Vor% weil der zweite Import from mod2 import *
den Namen datetime
im Namespace überschrieben hat, daher ist das erste import datetime
nicht mehr gültig.
Moral: So ist die Reihenfolge der Importe, die Art der Importe (aus x Import *) und das Bewusstsein für Importe innerhalb importierter Module - Angelegenheiten .
Diese Frage wurde vor einigen Wochen beantwortet, aber ich denke, ich kann die Antworten ein wenig klären. Zuerst ein paar Fakten.
1: In Python,
%Vor%ist fast genau dasselbe wie
%Vor%2: Wenn Python beim Ausführen von Code in einer Funktion auf eine Variable trifft, die noch nicht in der Funktion definiert wurde, wird im globalen Gültigkeitsbereich gesucht.
3: Python hat eine Optimierung für Funktionen namens "localhosts". Wenn Python eine Funktion in Token zerlegt, speichert es alle Variablen, die Sie zuweisen. Es weist jeder dieser Variablen eine Zahl aus einer lokalen monoton steigenden Ganzzahl zu. Wenn Python die Funktion ausführt, erstellt es ein Array mit so vielen Slots, wie es lokale Variablen gibt, und weist jedem Slot einen speziellen Wert zu, der bedeutet, dass "noch nicht zugewiesen wurde", und dort werden die Werte für diese Variablen gespeichert. Wenn Sie auf ein lokal verweisen, das noch nicht zugewiesen wurde, sieht Python diesen speziellen Wert und löst eine UnboundLocalValue-Ausnahme aus.
Die Bühne ist jetzt festgelegt. Ihr "from pprint import pprint" ist wirklich eine Form der Zuweisung. Python erstellt also eine lokale Variable namens "pprint", die die globale Variable verdeckt. Wenn Sie dann in der Funktion auf "pprint.pprint" verweisen, treffen Sie den speziellen Wert und Python löst die Ausnahme aus. Wenn Sie diese Import-Anweisung nicht in der Funktion hätten, würde Python die normale Look-in-Locals-First-To-Look-in-Globals-Auflösung verwenden und das pprint-Modul in globals finden.
Um dies zu verdeutlichen, können Sie das Schlüsselwort "global" verwenden. Natürlich haben Sie Ihr Problem bereits hinter sich gebracht, und ich weiß nicht, ob Sie wirklich "global" brauchten oder ob ein anderer Ansatz erforderlich war.
Tags und Links python scope binding identifier