Frage

Ich lief vor kurzem über diesen Fall von UnboundLocalError, die seltsam erscheint:

import pprint

def main():
    if 'pprint' in globals(): print 'pprint is in globals()'
    pprint.pprint('Spam')
    from pprint import pprint
    pprint('Eggs')

if __name__ == '__main__': main()

Welche erzeugt:

pprint is in globals()
Traceback (most recent call last):
  File "weird.py", line 9, in <module>
    if __name__ == '__main__': main()
  File "weird.py", line 5, in main
    pprint.pprint('Spam')
UnboundLocalError: local variable 'pprint' referenced before assignment

pprint ist eindeutig in globals gebunden und wird sich in locals in der folgenden Erklärung gebunden sein. Kann jemand eine Erklärung bieten, warum es hier nicht glücklich Lösung pprint auf die Bindung in globals ist?

Edit: Dank der guten Antworten, die ich meine Frage mit relevanten Terminologie klären können:

Beim Kompilieren der Kennung pprint wird als lokal auf den Rahmen markiert. Hat das Ausführungsmodell keinen Unterschied hat mit innerhalb des Rahmens wird die lokale Kennung gebunden? Kann es sagen, „beziehen sich auf die globale, bis diese Bytecode-Befehl Bindung auf, an welcher Stelle es Rebound an eine lokale Bindung war“, oder ist das Ausführungsmodell für das nicht-Konto?

War es hilfreich?

Lösung

Sieht aus wie Python die from pprint import pprint Linie und Markierungen pprint als Name lokal für main() vor sieht beliebigen Code auszuführen. Da Python denkt pprint eine lokale Variable sein soll, ist es mit pprint.pprint() Referenzierung bevor es mit der from..import Anweisung „Zuweisung“, wirft es diesen Fehler.

Das ist so viel Sinn, wie ich daraus machen kann.

Die Moral, ist natürlich immer jene import Aussagen an der Spitze des Bereichs zu setzen.

Andere Tipps

Wo ist die Überraschung? Alle Variable global zu einem Umfang, die Sie in diesem Rahmen neu zugewiesen wird lokal vom Compiler in diesen Umfang markiert.

Wenn die Einfuhren anders behandelt werden würde, , die wäre überraschend, imho.

Es kann einen Fall macht für die Module nicht nach Symbolen darin verwendeten Benennung oder umgekehrt, though.

Nun, das war interessant genug für mich ein wenig zu experimentieren und ich lese durch http: / /docs.python.org/reference/executionmodel.html

Dann einige Bastelei mit Ihrem Code hier und da getan hat, das ist, was ich finden kann:

code:

import pprint

def two():
    from pprint import pprint
    print globals()['pprint']
    pprint('Eggs')
    print globals()['pprint']

def main():
    if 'pprint' in globals():
        print 'pprint is in globals()'
    global  pprint
    print globals()['pprint']
    pprint.pprint('Spam')
    from pprint import pprint
    print globals()['pprint']
    pprint('Eggs')

def three():
    print globals()['pprint']
    pprint.pprint('Spam')

if __name__ == '__main__':
    two()
    print('\n')
    three()
    print('\n')
    main()

Ausgabe:

<module 'pprint' from '/usr/lib/python2.5/pprint.pyc'>
'Eggs'
<module 'pprint' from '/usr/lib/python2.5/pprint.pyc'>

<module 'pprint' from '/usr/lib/python2.5/pprint.pyc'>
'Spam'

pprint is in globals()
<module 'pprint' from '/usr/lib/python2.5/pprint.pyc'>
'Spam'
<function pprint at 0xb7d596f4>
'Eggs'

Bei dem Verfahren two() from pprint import pprint aber überschreibt nicht den Namen pprint in globals, da das global Schlüsselwort nicht im Rahmen des two() verwendet.

In Verfahren three() da es keine Erklärung von pprint Namen in lokalen Bereich wird standardmäßig die globalen Namen pprint, die ein Modul

Während in main(), zuerst das Stichwort global verwendet wird, , um alle Verweise in dem Anwendungsbereich der Methode pprint main() zum global Namen pprint beziehen. Die, wie wir ein Modul zunächst sehen können und in dem global namespace mit einem Verfahren außer Kraft gesetzt, wie wir die from pprint import pprint

tun

Obwohl dies nicht die Frage als solche zu beantworten, aber dennoch seine einige interessante Tatsache, denke ich.

=====================

Bearbeiten Eine weitere interessante Sache.

Wenn Sie ein Modul haben sagen:

mod1

from datetime import    datetime

def foo():
    print "bar"

und ein anderes Verfahren sagen:

mod2

import  datetime
from mod1 import *

if __name__ == '__main__':
    print datetime.datetime.now()

, die auf den ersten Blick scheinbar korrekt, da das Modul datetime in mod2 importiert haben.

jetzt, wenn Sie versuchen, mod2 als Skript ausführen wird es einen Fehler aus:

Traceback (most recent call last):
  File "mod2.py", line 5, in <module>
    print datetime.datetime.now()
AttributeError: type object 'datetime.datetime' has no attribute 'datetime'

, da der zweite Import from mod2 import * den Namen datetime im Namensraum außer Kraft gesetzt hat, daher der erste import datetime ist nicht mehr gültig.

Moral. So ist die Reihenfolge der Importe, die Art des Imports (von x Import *) und das Bewusstsein für die Einfuhr in importierten Module - Angelegenheiten

Diese Frage wurde vor einigen Wochen beantwortet, aber ich denke, dass ich die Antworten ein wenig klären können. Zunächst einige Fakten.

1: In Python,

import foo

ist fast genau die gleiche wie

foo = __import__("foo", globals(), locals(), [], -1)

. 2: Wenn Code in einer Funktion ausgeführt wird, wenn Python eine Variable trifft, die in der Funktion definiert wird noch nicht, es sieht im globalen Bereich

3: Python hat eine Optimierung für Funktionen verwendet, genannt „Einheimischen“. Wenn Python eine Funktion tokenizes, hält es den Überblick über alle Variablen Sie zuweisen. Er weist jede dieser Variablen eine Zahl von einem lokalen monoton steigenden integer. Wenn Python die Funktion ausgeführt wird, erstellt sie ein Array mit so vielen Schlitzen wie es lokale Variablen sind, und es weist jeder Schlitz ein besonderer Wert, der bedeutet „wurde nicht zugewiesen noch“, und das ist, in dem die Werte für diese Variablen gespeichert sind. Wenn Sie eine lokale Referenz, die nicht noch zugewiesen hat, sieht Python, dass besonderen Wert und löst eine UnboundLocalValue Ausnahme.

Die Bühne ist nun eingestellt. Ihr „von pprint Import pprint“ ist wirklich eine Form der Zuordnung. So Python erstellt eine lokale Variable mit dem Namen „pprint“, die die globale Variable verschliesst. Wenn Sie dann auf „pprint.pprint“ in der Funktion beziehen, drücken Sie den besonderen Wert und Python wirft die Ausnahme. Wenn Sie nicht, dass die Import-Anweisung in der Funktion haben, würde Python verwenden, um die normale Look-in-Einheimischen-first-then-Look-in-Globals Auflösung und die pprint Modul in Globals finden.

Um dies disambiguate Sie das „global“ Schlüsselwort verwenden können. Natürlich jetzt haben Sie bereits Vergangenheit Ihres Problems gearbeitet, und ich weiß nicht, ob Sie wirklich für erforderlich „global“ oder wurde ein anderer Ansatz genannt.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top