Python globals, Locals und UnboundLocalError

8

Ich habe kürzlich diesen Fall von UnboundLocalError durchgelaufen, was merkwürdig erscheint:

%Vor%

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?

    
cdleary 01.01.2009, 04:48
quelle

4 Antworten

4

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.

    
Triptych 01.01.2009, 06:02
quelle
6

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.

    
Albert Visser 01.01.2009 09:42
quelle
5

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

ist

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

machen

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

%Vor%

und eine andere Methode sagen:

mod2

%Vor%

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 .

    
JV. 01.01.2009 08:21
quelle
4

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.

    
Larry Hastings 27.01.2010 11:25
quelle

Tags und Links