Domanda

Mi sono imbattuto recentemente in questo caso di UnboundLocalError , il che sembra strano:

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()

Che produce:

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 è chiaramente associato in globals e verrà associato in locals nella seguente dichiarazione. Qualcuno può offrire una spiegazione del perché non è felice di risolvere pprint al binding in globals qui?

Modifica: Grazie alle buone risposte posso chiarire la mia domanda con una terminologia pertinente:

Al momento della compilazione l'identificatore pprint è contrassegnato come locale al frame. Il modello esecutivo non ha distinzioni dove all'interno del frame è associato l'identificatore locale? Può dire "fare riferimento all'associazione globale fino a quando questa istruzione bytecode, a quel punto è stata rimbalzata ad un'associazione locale," o il modello di esecuzione non tiene conto di questo?

È stato utile?

Soluzione

Sembra che Python veda il dalla riga import pprint e contrassegni pprint come un nome locale in main () prima di eseguendo qualsiasi codice. Poiché Python pensa che pprint dovrebbe essere una variabile locale, facendo riferimento a pprint.pprint () prima di " assegnando " con l'istruzione from..import , genera quell'errore.

È tutto il più sensato possibile.

La morale, ovviamente, è sempre mettere quelle import in cima all'ambito.

Altri suggerimenti

Dov'è la sorpresa? Qualsiasi variabile globale in un ambito che si riassegna all'interno di tale ambito è contrassegnata come locale per tale ambito dal compilatore.

Se le importazioni fossero gestite in modo diverso, quello sarebbe sorprendente imho.

Potrebbe essere utile non nominare i moduli dopo i simboli utilizzati al loro interno, o viceversa, tuttavia.

Beh, è ??stato abbastanza interessante per me sperimentare un po 'e ho letto http: / /docs.python.org/reference/executionmodel.html

Poi ho armeggiato un po 'con il tuo codice qua e là, questo è quello che ho potuto trovare:

codice:

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()

uscita:

<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'

Nel metodo due () dall'importazione pprint ma non sovrascrive il nome pprint in globals , poiché la parola chiave globale non è non utilizzata nell'ambito di due () .

Nel metodo tre () poiché non esiste una dichiarazione del nome pprint nell'ambito locale, viene impostato automaticamente il nome globale pprint che è un modulo

Considerando che in main () , all'inizio viene usata la parola chiave global quindi tutti i riferimenti a pprint in l'ambito del metodo main () farà riferimento al global name pprint . Che come possiamo vedere all'inizio è un modulo ed è scavalcato nello spazio dei nomi global con un metodo come facciamo il from pprint import pprint

Anche se questo potrebbe non rispondere alla domanda in quanto tale, ma penso che sia un fatto interessante, penso.

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

Modifica Un'altra cosa interessante.

Se hai un modulo dire:

mod1

from datetime import    datetime

def foo():
    print "bar"

e un altro metodo dice:

mod2

import  datetime
from mod1 import *

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

che a prima vista è apparentemente corretto poiché hai importato il modulo datetime in mod2 .

ora se si tenta di eseguire mod2 come script, verrà generato un errore:

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'

perché la seconda importazione dall'importazione mod2 * ha sostituito il nome datetime nello spazio dei nomi, quindi il primo import datetime non è più valido .

Morale: quindi l'ordine delle importazioni, la natura delle importazioni (da x import *) e la consapevolezza delle importazioni all'interno dei moduli importati - importa .

A questa domanda è stata data risposta diverse settimane fa, ma penso di poter chiarire un po 'le risposte. Innanzitutto alcuni fatti.

1: in Python,

import foo

è quasi identico a

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

2: quando si esegue il codice in una funzione, se Python rileva una variabile che non è stata ancora definita nella funzione, appare nell'ambito globale.

3: Python ha un'ottimizzazione che utilizza per le funzioni chiamate "locali". Quando Python tokenizza una funzione, tiene traccia di tutte le variabili assegnate a. Assegna a ciascuna di queste variabili un numero da un intero locale monotonicamente crescente. Quando Python esegue la funzione, crea un array con tutti gli slot quante sono le variabili locali e assegna a ciascuno slot un valore speciale che significa che "non è stato ancora assegnato a", ed è lì che sono memorizzati i valori per quelle variabili . Se fai riferimento a un locale a cui non è stato ancora assegnato, Python vede quel valore speciale e genera un'eccezione UnboundLocalValue.

Lo stage è ora impostato. Il tuo " da pprint import pprint " è davvero una forma di incarico. Quindi Python crea una variabile locale chiamata " pprint " che occlude la variabile globale. Quindi, quando fai riferimento a " pprint.pprint " nella funzione, premi il valore speciale e Python genera l'eccezione. Se non avessi quell'istruzione import nella funzione, Python userebbe la normale risoluzione look-in-locals-first-poi-look-in-globals e troverebbe il modulo pprint in globals.

Per chiarire questo, puoi utilizzare il " global " parola chiave. Ovviamente ormai hai già superato il tuo problema e non so se hai davvero bisogno di " global " o se fosse richiesto un altro approccio.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top