2012-10-11 10 views
9

Sono perplesso dal modo in cui le importazioni circolari vengono gestite in Python. Ho cercato di distillare una domanda minima e non penso che questa esatta variante sia stata richiesta prima. In sostanza, sto vedendo una differenza traDifferenza tra "import lib.foo" e "import lib.foo as f" in Python

import lib.foo 

e

import lib.foo as f 

quando ho una dipendenza circolare tra il lib.foo e lib.bar. Mi aspettavo che entrambi avrebbero funzionato allo stesso modo: il modulo (possibilmente half-inizializzato) sarebbe stato trovato in sys.modules e inserito nello spazio dei nomi locale. (Da test ho notato che import lib.foo mette davvero lib nel namespace locale -. Va bene, con la sintassi che farò lib.foo.something comunque)

Tuttavia, se lib.foo è già in sys.modules, poi import lib.foo as f tenta di accedere foo come attributo su lib e solleva AttributeError. Perché il comportamento (apparentemente) dipende dalla presenza in sys.modules?

Inoltre, dove viene documentato questo comportamento? Non credo che lo Python import statement reference spieghi questo comportamento, o almeno non riesco a estrarlo :-)

Tutto sommato sto provando a cambiare un codice di base per utilizzare lo stile oft recommended in cui si importano i moduli, non simboli nei moduli:

Ma ciò non riesce quando ci sono importazioni circolari tra i due moduli. Mi aspettavo che funzionasse finché le definizioni di livello superiore nei due moduli non dipendono l'una dall'altra (ad esempio, nessuna sottoclasse in moduleB con una classe base in moduleA).

script di test:

#!/bin/sh 
rm -r lib; mkdir lib 

touch lib/__init__.py 

cat > lib/foo.py <<EOF 
# lib.foo module 
print '{ foo' 
#import lib.bar # works 
import lib.bar as b # also works 
#from lib import bar # also works 
print 'foo }' 
EOF 

cat > lib/bar.py <<EOF 
# lib.bar module 
print '{ bar' 
#import lib.foo # works 
import lib.foo as f # AttributeError: 'module' object has no attribute 'foo' 
#from lib import foo # ImportError: cannot import name foo 
print 'bar }' 
EOF 

python -c 'import lib.foo' 
+0

Link http://google-styleguide.googlecode.com/svn/trunk/pyguide.html?showone=Imports#Imports è rotto - sarebbe bello leggere –

risposta

6

Quando dici import lib.foo as f ciò che si sta dicendo di fare Python è l'equivalente di import lib.foo; f = lib.foo a livello bytecode. Si finisce con un AttributeError nel problema che viene chiesto perché lib in questo caso non ha ancora impostato foo come attributo. Python non ha completato l'importazione di lib.foo quando tenta di eseguire l'assegnazione e quindi non ha ancora impostato l'attributo su lib; guarda il sorgente Python 3.3 per l'importazione dove puoi vedere dove un module is loaded contro le istruzioni coppia più in basso dove uno module is set on its parent.

Qui è dove si trovano alcuni problemi di importazione circolare. È necessario lasciare l'importazione per lib.foo completa prima di provare ad accedere a lib.foo, altrimenti l'attributo su lib semplicemente non esiste ancora per il bytecode per l'accesso. Questo potrebbe essere il motivo per cui ritieni di non utilizzare definizioni di primo livello direttamente nel tuo codice, ma in realtà sei attraverso le istruzioni di importazione.

+0

Grazie per la risposta! Quindi quando importo 'lib.foo',' lib' viene prima importato e quando 'lib.foo' viene importato, un attributo' foo' è impostato in 'lib'. Ecco perché 'lib.foo.something' funziona più tardi: trova l'attributo' foo' * nel pacchetto 'lib' - che spiega anche perché' import lib.foo' mette 'lib' nello spazio dei nomi locale. –

+0

Sì, è tutto corretto. –