2011-05-18 15 views
14

Tome el ejemplo de código siguiente:desde <module> importar ... en __init__.py hace visible el nombre del módulo?

Archivo package1/__init__.py:

from moduleB import foo 
print moduleB.__name__ 

Archivo package1/moduleB.py:

def foo(): pass 

Luego, desde el directorio actual:

>>> import package1 
package1.moduleB 

Este código funciona en CPyt hon. Lo que me sorprende al respecto es que la declaración from ... import en __init__.py hace que el nombre moduleBsea visible. De acuerdo con Python documentation, esto no debería ser el caso:

La forma de no se une el nombre del módulo

Podría alguien explicar por qué CPython funciona de esa manera? ¿Hay alguna documentación que describa esto en detalle?

+0

¿Está seguro de que no hay 'import moduleB' antes de eso? – JBernardo

+0

Sí, estoy seguro. Esos son los archivos completos sobre los que se puede reproducir la situación. – yole

+0

Lo intenté y funciona en Python2.7 pero no en Python3.2 ... – JBernardo

Respuesta

5

La documentación que engañó como está escrito para describir el caso más común de importación un módulo desde fuera del paquete principal que lo contiene.

Por ejemplo, usando "desde el submódulo de importación de ejemplo" en mi propio código, donde "ejemplo" es una biblioteca de terceros completamente desconectada de mi propio código, no vincula el nombre "ejemplo". Todavía importa ambos los módulos example/__ init__.py y example/submodule.py, crea dos objetos de módulo y asigna example.submodule al segundo objeto de módulo.

Pero, "from..import" de nombres de un submódulo debe establecer el atributo de submódulo en el objeto de paquete principal. Considere si no lo hizo:

  1. paquete/__ init__.py se ejecuta cuando se importa el paquete.

  2. That __init__ does "from submodule import name".

  3. En algún momento posterior, otro código completamente diferente "import package package.submodule".

En el paso 3, ya sea sys.modules [ "package.submodule"] no existe, en cuyo caso la carga de nuevo le dará dos objetos de módulo diferentes en diferentes ámbitos; o sys.modules ["paquete.submódulo "] existirá pero" submódulo "no será un atributo del objeto del paquete primario (sys.modules [" paquete "]), y" import package.submodule "no hará nada. Sin embargo, si no hace nada, el código mediante la importación no puede acceder submódulo como un atributo de paquete!


en teoría, la forma en la importación funciona un submódulo podría ser cambiado si el resto de la maquinaria de importación fue cambiado para que coincida.

Si sólo necesita para saber qué importará un submódulo S del paquete P, en pocas palabras:

  1. Asegúrese de que P se importe, o impórtelo de lo contrario. (Este paso se repite para manejar "importar A.B.C.D").
  2. Ejecute S.py para obtener un objeto de módulo. (Omitir detalles de archivos .pyc, etc.)
  3. Almacenar objeto de módulo en sys.modules ["P.S"].
  4. setattr(sys.modules["P"], "S", sys.modules["P.S"])
  5. Si esa importación era del tipo "importar P.S", enlaza "P" en el ámbito local.
+0

Y el alcance de la resolución de nombres no calificados dentro de la \ _ \ _ init__.py de un paquete incluye los atributos del objeto del paquete, ¿verdad? – yole

+0

@yole: Sí, globals() en \ _ \ _ init \ _ \ _. Py es sys.modules ["paquete"]. \ _ \ _ Dict \ _ \ _. –

0

esto se debe a que __init__.py se representa a sí mismo como el objeto del módulo package1 en el tiempo de ejecución, por lo que cada archivo .py se definirá como un submódulo. y reescribir __all__ no tendrá ningún sentido. puede crear otro archivo, por ejemplo example.py, y rellenarlo con el mismo código en __init__.py y aumentará NameError.

Creo CPython tiempo de ejecución toma algoritmo especial cuando __init__.py en busca de las variables difieren de otros archivos de Python, puede ser como este:

looking for variable named "moduleB" 
if not found: 
    if __file__ == '__init__.py': #dont raise NameError, looking for file named moduleB.py 
     if current dir contains file named "moduleB.py": 
         import moduleB 
     else: 
        raise namerror 
+1

Esto no es tan simple como eso. Si no importa el módulo B en \ _ \ _ init__.py, el nombre no se resolverá. – yole

+0

@yole sí, lo siento. Me olvido de reiniciar Python Shell después de la modificación – MBarsi

Cuestiones relacionadas