para - lista de modulos de python
Python: importar un subpaquete o submódulo (3)
Al haber usado paquetes planos, no esperaba el problema que encontré con los paquetes anidados. Aquí está…
Disposición del directorio
dir
|
+-- test.py
|
+-- package
|
+-- __init__.py
|
+-- subpackage
|
+-- __init__.py
|
+-- module.py
Contenido de init .py
Tanto el package/__init__.py
como el package/subpackage/__init__.py
están vacíos.
Contenido de module.py
# file `package/subpackage/module.py`
attribute1 = "value 1"
attribute2 = "value 2"
attribute3 = "value 3"
# and as many more as you want...
Contenido de test.py
(3 versiones)
Versión 1
# file test.py
from package.subpackage.module import *
print attribute1 # OK
Esa es la forma incorrecta e insegura de importar cosas (importar todo en un volumen), pero funciona.
Versión 2
# file test.py
import package.subpackage.module
from package.subpackage import module # Alternative
from module import attribute1
Una forma más segura de importar, elemento por elemento, pero falla, Python no quiere esto: falla con el mensaje: "Ningún módulo denominado módulo". Sin embargo …
# file test.py
import package.subpackage.module
from package.subpackage import module # Alternative
print module # Surprise here
... dice <module ''package.subpackage.module'' from ''...''>
. Entonces ese es un módulo, pero eso no es un módulo / -P 8-O ... uh
Versión 3
# file test.py v3
from package.subpackage.module import attribute1
print attribute1 # OK
Este funciona Entonces, ¿estás obligado a usar el prefijo de sobrecarga todo el tiempo o usar la forma insegura como en la versión 1 y no permitido por Python para usarlo de la manera más segura? La mejor manera, que es segura y evitar el prefijo largo innecesario, es la única que Python rechaza? ¿Es esto porque ama la import *
o porque ama los prefijos excesivos (lo que no ayuda a hacer cumplir esta práctica) ?.
Perdón por las palabras duras, pero son dos días que trato de evitar este comportamiento estúpido. A menos que estuviera totalmente equivocado en alguna parte, esto me dejará con la sensación de que algo está realmente roto en el modelo de paquetes y subpaquetes de Python.
Notas
- No quiero confiar en
sys.path
, para evitar los efectos secundarios globales, ni en los archivos*.pth
, que son solo otra forma de jugar consys.path
con los mismos efectos globales. Para que la solución sea limpia, tiene que ser solo local. O bien Python puede manejar el subpaquete, o no, pero no debería requerir jugar con la configuración global para poder manejar cosas locales. - También probé usar importaciones en
package/subpackage/__init__.py
, pero no resolvió nada, hace lo mismo, y se queja de que elsubpackage
no es un módulo conocido, mientras que elprint subpackage
dice que es un módulo (comportamiento extraño, de nuevo).
Puede ser que estoy completamente equivocado (la opción que preferiría), pero esto me hace sentir muy decepcionado con Python.
¿Alguna otra forma conocida además de las tres que probé? Algo que no sé?
(suspiro)
-----% <----- editar ----->% -----
Conclusión hasta el momento (después de los comentarios de la gente)
No hay nada como un subpaquete real en Python, ya que todas las referencias de paquetes van a un dictionario global, lo que significa que no hay un diccionario local, lo que implica que no hay forma de administrar la referencia del paquete local.
Debe usar el prefijo completo o el prefijo corto o el alias. Como en:
Versión de prefijo completo
from package.subpackage.module import attribute1
# An repeat it again an again
# But after that, you can simply:
use_of (attribute1)
Versión de prefijo corto (pero prefijo repetido)
from package.subpackage import module
# Short but then you have to do:
use_of (module.attribute1)
# and repeat the prefix at every use place
O bien, una variación de lo anterior.
from package.subpackage import module as m
use_of (m.attribute1)
# `m` is a shorter prefix, but you could as well
# define a more meaningful name after the context
Versión factorizada
Si no te importa importar una entidad múltiple de una sola vez en un lote, puedes:
from package.subpackage.module import attribute1, attribute2
# and etc.
No en mi primer gusto favorito (prefiero tener un extracto de importación por entidad importada), pero puede ser el que yo personalmente favorezca.
Actualización (14/09/2012):
Finalmente parece estar bien en la práctica, excepto con un comentario sobre el diseño. En lugar de lo anterior, utilicé:
from package.subpackage.module import (
attribute1,
attribute2,
attribute3,
...) # and etc.
El motivo # 2 falla porque sys.modules[''module'']
no existe (la rutina de importación tiene su propio alcance, y no puede ver el nombre local del module
), y no hay ningún módulo o paquete en el disco. Tenga en cuenta que puede separar varios nombres importados por comas.
from package.subpackage.module import attribute1, attribute2, attribute3
También:
from package.subpackage import module
print module.attribute1
Parece que no entiende cómo la import
busca módulos. Cuando utiliza una declaración de importación, siempre busca la ruta real del módulo (y / o sys.modules
); no hace uso de objetos de módulo en el espacio de nombres local que existen debido a importaciones anteriores. Cuando tu lo hagas:
import package.subpackage.module
from package.subpackage import module
from module import attribute1
La segunda línea busca un paquete llamado package.subpackage
e importa el module
de ese paquete. Esta línea no tiene efecto en la tercera línea. La tercera línea solo busca un módulo llamado module
y no encuentra uno. No "reutiliza" el objeto llamado module
que obtuvo de la línea anterior.
En otras palabras, from someModule import ...
no significa "del módulo llamado algúnModulo que importé antes ..." significa "del módulo llamado algúnMódulo que se encuentra en sys.path ...". No hay forma de construir "incrementalmente" la ruta de un módulo importando los paquetes que conducen a ella. Siempre debe consultar todo el nombre del módulo al importar.
No está claro lo que estás tratando de lograr. Si solo desea importar el atributo de objeto particular1, solo haga lo mismo from package.subpackage.module import attribute1
y termine con él. No necesita preocuparse por el package.subpackage.module
largo una vez que haya importado el nombre que desea de él.
Si desea tener acceso al módulo para acceder a otros nombres más adelante, puede hacerlo from package.subpackage import module
y, como ha visto, puede hacer module.attribute1
y todo lo que desee.
Si desea ambas cosas , es decir, si desea que el attribute1
esté directamente accesible y desea que se pueda acceder al module
, solo haga lo siguiente:
from package.subpackage import module
from package.subpackage.module import attribute1
attribute1 # works
module.someOtherAttribute # also works
Si no le gusta escribir package.subpackage
incluso dos veces, puede crear manualmente una referencia local al atributo1:
from package.subpackage import module
attribute1 = module.attribute1
attribute1 # works
module.someOtherAttribute #also works
Si todo lo que intenta hacer es obtener el atributo 1 en su espacio de nombres global, la versión 3 parece estar bien. ¿Por qué es el prefijo overkill?
En la versión 2, en lugar de
from module import attribute1
tu puedes hacer
attribute1 = module.attribute1