Habiendo usado ya paquetes planos, no esperaba el problema que encontré con los paquetes anidados. Aquí está…
Diseño de directorio
dir
|
+-- test.py
|
+-- package
|
+-- __init__.py
|
+-- subpackage
|
+-- __init__.py
|
+-- module.py
Contenido de init .py
Ambos package/__init__.py
y 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 mala e insegura de importar cosas (importar todo a granel), 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 llamado 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 eso 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, ¿se ve obligado a usar el prefijo overkill todo el tiempo o usa la forma insegura como en la versión n. ° 1 y Python no le permite usar la forma práctica y segura? La mejor manera, que es segura y evita el prefijo largo innecesario, ¿es la única que Python rechaza? ¿Es esto porque ama import *
o porque ama los prefijos demasiado largos (lo que no ayuda a hacer cumplir esta práctica) ?.
Perdón por las palabras difíciles, pero hace dos días que intento solucionar este comportamiento estúpido. A menos que esté totalmente equivocado en alguna parte, esto me dejará con la sensación de que algo está realmente roto en el modelo de paquete y subpaquetes de Python.
Notas
- No quiero depender de
sys.path
, para evitar efectos secundarios globales, ni de*.pth
archivos, que son solo otra forma de jugarsys.path
con los mismos efectos globales. Para que la solución esté limpia, debe ser solo local. Python es capaz de manejar subpaquetes, o no, pero no debería requerir jugar con la configuración global para poder manejar cosas locales. - También intenté usar importaciones
package/subpackage/__init__.py
, pero no resolvió nada, hace lo mismo y se queja desubpackage
que no es un módulo conocido, mientras queprint subpackage
dice que es un módulo (comportamiento extraño, de nuevo).
Puede que me equivoque por completo (la opción que preferiría), pero esto me decepcionó mucho con Python.
¿Alguna otra forma conocida además de las tres que probé? ¿Algo que no conozco?
(suspiro)
-----% <----- editar ----->% -----
Conclusión hasta ahora (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 diccionario global, solo, lo que significa que no hay un diccionario local, lo que implica que no hay forma de administrar la referencia del paquete local.
Tienes que usar prefijo completo o prefijo corto o 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 le importa importar varias entidades a la vez en un lote, puede:
from package.subpackage.module import attribute1, attribute2
# and etc.
No es mi primer gusto favorito (prefiero tener una declaración de importación por entidad importada), pero puede que sea la que prefiera personalmente.
Actualización (2012-09-14):
Finalmente parece estar bien en la práctica, excepto con un comentario sobre el diseño. En lugar de lo anterior, usé:
from package.subpackage.module import (
attribute1,
attribute2,
attribute3,
...) # and etc.