¿Cómo puedo hacer importaciones relativas en Python?

Resuelto Joril asked hace 16 años • 16 respuestas

Imagine esta estructura de directorios:

app/
   __init__.py
   sub1/
      __init__.py
      mod1.py
   sub2/
      __init__.py
      mod2.py

Estoy codificando mod1y 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.pathtrucos 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, subXetc.).

El comportamiento que estoy buscando es el mismo que se describe en PEP 366 ( gracias John B ).

Joril avatar Sep 16 '08 21:09 Joril
Aceptado

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.

John B avatar Sep 16 '2008 14:09 John B

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 appy 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-packageerror.

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.

Pankaj avatar Mar 17 '2013 07:03 Pankaj
main.py
setup.py
app/ ->
    __init__.py
    package_a/ ->
       __init__.py
       module_a.py
    package_b/ ->
       __init__.py
       module_b.py
  1. Tu corres python main.py.
  2. main.pyhace:import app.package_a.module_a
  3. module_a.pyhaceimport 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 appen su PYTHONPATH. main.pypodría estar en cualquier lugar entonces.

Por lo tanto, escribe un setup.pypara copiar (instalar) todo el paquete de la aplicación y los subpaquetes en las carpetas de Python del sistema de destino y main.pyen las carpetas de script del sistema de destino.

nosklo avatar Jan 21 '2009 12:01 nosklo

"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.

lesnik avatar Nov 19 '2011 16:11 lesnik

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')