¿Cómo puedo hacer importaciones relativas en Python?
Imagine esta estructura de directorios:
app/
__init__.py
sub1/
__init__.py
mod1.py
sub2/
__init__.py
mod2.py
Estoy codificando mod1
y necesito importar algo de mod2
. ¿Cómo debería hacerlo?
Lo intenté from ..sub2 import mod2
, pero aparece el mensaje "Intento de importación relativa sin paquete".
Busqué en Google, pero sólo encontré sys.path
trucos de "manipulación". ¿No existe una manera limpia?
Todos mis __init__.py
's están actualmente vacíos.
Estoy intentando hacer esto porque sub2 contiene clases que se comparten entre subpaquetes ( sub1
, subX
etc.).
El comportamiento que estoy buscando es el mismo que se describe en PEP 366 ( gracias John B ).
El problema es que estás ejecutando el módulo como '__main__' pasando mod1.py como argumento al intérprete.
Del PEP 328 :
Las importaciones relativas utilizan el atributo __name__ de un módulo para determinar la posición de ese módulo en la jerarquía del paquete. Si el nombre del módulo no contiene ninguna información del paquete (por ejemplo, está configurado en '__main__'), las importaciones relativas se resuelven como si el módulo fuera un módulo de nivel superior, independientemente de dónde se encuentre realmente el módulo en el sistema de archivos.
En Python 2.6, están agregando la capacidad de hacer referencia a módulos en relación con el módulo principal. PEP 366 describe el cambio.
Aquí está la solución que funciona para mí:
Hago las importaciones relativas como from ..sub2 import mod2
y luego, si quiero ejecutar mod1.py
, voy al directorio principal app
y ejecuto el módulo usando el modificador python -m como python -m app.sub1.mod1
.
La verdadera razón por la que ocurre este problema con las importaciones relativas es que las importaciones relativas funcionan tomando la __name__
propiedad del módulo. Si el módulo se ejecuta directamente, __name__
está configurado en __main__
y no contiene ninguna información sobre la estructura del paquete. Y es por eso que Python se queja del relative import in non-package
error.
Entonces, al usar el modificador -m, usted proporciona la información de la estructura del paquete a Python, a través de la cual puede resolver las importaciones relativas con éxito.
Me he encontrado con este problema muchas veces al realizar importaciones relativas. Y, después de leer todas las respuestas anteriores, todavía no podía descubrir cómo resolverlo, de forma limpia, sin necesidad de poner código repetitivo en todos los archivos. (Aunque algunos de los comentarios fueron realmente útiles, gracias a @ncoghlan y @XiongChiamiov)
Espero que esto ayude a alguien que esté luchando con un problema de importaciones relativas, porque pasar por el PEP realmente no es divertido.
main.py
setup.py
app/ ->
__init__.py
package_a/ ->
__init__.py
module_a.py
package_b/ ->
__init__.py
module_b.py
- Tu corres
python main.py
. main.py
hace:import app.package_a.module_a
module_a.py
haceimport app.package_b.module_b
Alternativamente, 2 o 3 podrían usar:from app.package_a import module_a
Eso funcionará siempre que lo tenga app
en su PYTHONPATH. main.py
podría estar en cualquier lugar entonces.
Por lo tanto, escribe un setup.py
para copiar (instalar) todo el paquete de la aplicación y los subpaquetes en las carpetas de Python del sistema de destino y main.py
en las carpetas de script del sistema de destino.
"Guido ve la ejecución de scripts dentro de un paquete como un antipatrón" (rechazado PEP-3122 )
He pasado mucho tiempo tratando de encontrar una solución, leyendo publicaciones relacionadas aquí en Stack Overflow y diciéndome "¡debe haber una manera mejor!". Parece que no lo hay.
Esto se soluciona al 100%:
- aplicación/
- principal.py
- ajustes/
- configuración_local.py
Importar configuración/local_setting.py en app/main.py:
principal.py:
import sys
sys.path.insert(0, "../settings")
try:
from local_settings import *
except ImportError:
print('No Import')