2012-10-11 42 views
9

Me desconcierta cómo se manejan las importaciones circulares en Python. Intenté extraer una pregunta mínima y no creo que esta variante exacta se haya preguntado antes. Básicamente, estoy viendo una diferencia entreDiferencia entre "importar lib.foo" e "importar lib.foo como f" en Python

import lib.foo 

y

import lib.foo as f 

cuando tengo una dependencia circular entre lib.foo y lib.bar. Esperaba que ambos funcionaran de la misma manera: el módulo (posiblemente a mitad de inicializado) se encontraría en sys.modules y se colocaría en el espacio de nombres local. (A partir de las pruebas me di cuenta de que realmente pone import lib.foolib en el espacio de nombres local, -. Bien, con la sintaxis que lo haré de todos modos lib.foo.something)

Sin embargo, si ya está en lib.foosys.modules, a continuación, import lib.foo as f intenta acceder foo como un atributo en lib y aumenta AttributeError. ¿Por qué el comportamiento (aparentemente) depende de la presencia en sys.modules?

Además, ¿dónde está documentado este comportamiento? No creo que el Python import statement reference explique este comportamiento, o al menos no pude extraerlo :-)

En general, estoy intentando cambiar un código base para usar el estilo oft recommended donde importa módulos, no símbolos en los módulos:

from project.package import moduleA 
from project.package import moduleB 

Pero eso falla cuando hay importaciones circulares entre los dos módulos. Esperaba que funcionara siempre que las definiciones de nivel superior en los dos módulos no dependieran entre sí (por ejemplo, ninguna subclase en moduleB con una clase base en moduleA).

escritura de la prueba:

#!/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

Enlace http://google-styleguide.googlecode.com/svn/trunk/pyguide.html?showone=Imports#Imports está roto - sería bueno leer –

Respuesta

6

Cuando dice import lib.foo as f lo que le está diciendo a Python que hacer es el equivalente de import lib.foo; f = lib.foo a nivel de código de bytes. Usted termina con un AttributeError en el problema que se le pregunta porque lib en este caso no tiene foo establecido todavía como un atributo. Python no ha completado su importación de lib.foo cuando intenta hacer la asignación y por lo tanto no ha establecido el atributo todavía en lib; mira la fuente de importación de Python 3.3 donde puedes ver dónde un module is loaded vs. declaraciones de pareja más abajo donde un module is set on its parent.

Aquí es donde termina con algunos problemas circulares de importación. Debes dejar que la importación para lib.foo se complete antes de intentar acceder al lib.foo, de lo contrario, el atributo en lib simplemente no existirá aún para que el bytecode acceda. Esta podría ser la razón por la que cree que no está utilizando ninguna definición de nivel superior directamente en su código, pero en realidad está en sus declaraciones de importación.

+0

¡Gracias por la respuesta! Entonces cuando importo 'lib.foo',' lib' primero se importa y cuando 'lib.foo' se importa, un atributo' foo' se establece en 'lib'. Es por eso que 'lib.foo.something' funciona más tarde: encuentra el atributo' foo' * en el paquete 'lib', que también explica por qué' import lib.foo' pone 'lib' en el espacio de nombres local. –

+0

Sí, eso es todo correcto. –

Cuestiones relacionadas