¿Cómo hacer importaciones relativas en Python?



7 Answers

main.py
setup.py
app/ ->
    __init__.py
    package_a/ ->
       __init__.py
       module_a.py
    package_b/ ->
       __init__.py
       module_b.py
  1. Ejecuta python main.py
  2. main.py hace: import app.package_a.module_a
  3. module_a.py import app.package_b.module_b

Alternativamente 2 o 3 podrían usar: from app.package_a import module_a

Eso funcionará siempre y cuando tengas la app en tu PYTHONPATH. main.py podría estar en cualquier lugar entonces.

Por lo tanto, escribe un setup.py para copiar (instalar) todo el paquete de aplicaciones y subpaquetes en las carpetas python del sistema de destino, y main.py para main.py las carpetas de scripts del sistema.

Question

Imagina esta estructura de directorio:

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?

Intenté from ..sub2 import mod2 pero from ..sub2 import mod2 una "Intento de importación relativa en non-package".

Busqué en Google pero solo sys.path "hacks de manipulación de sys.path ". ¿No hay una manera limpia?

Editar: todos mis __init__.py están actualmente vacíos

Edit2: estoy intentando hacer esto porque sub2 contiene clases que se comparten en subX ( subX , subX , etc.).

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




Esto se resuelve al 100%:

  • app /
    • main.py
  • configuraciones /
    • local_setings.py

Importar configuraciones / local_setting.py en la aplicación / main.py:

main.py:

import sys
sys.path.insert(0, "../settings")


try:
    from local_settings import *
except ImportError:
    print('No Import')



"Guido ve la ejecución de scripts dentro de un paquete como un antipatrón" (rechazó PEP-3122 )

He pasado tanto tiempo tratando de encontrar una solución, leyendo publicaciones relacionadas aquí en y diciéndome a mí mismo "¡debe haber una mejor manera!". Parece que no hay.




Como dice @EvgeniSergeev en los comentarios al PO, puede importar código de un archivo .py en una ubicación arbitraria con:

import imp

foo = imp.load_source('module.name', '/path/to/file.py')
foo.MyClass()

Esto se toma de esta respuesta SO .




De http://docs.python.org/whatsnew/2.5.html#pep-328-absolute-and-relative-imports ,

En Python 2.5, puede cambiar el comportamiento de importación a importaciones absolutas utilizando una from __future__ import absolute_import . Este comportamiento de importación absoluta se convertirá en el predeterminado en una versión futura (probablemente Python 2.7). Una vez que las importaciones absolutas son las predeterminadas, la import string siempre encontrará la versión de la biblioteca estándar. Se sugiere que los usuarios comiencen a usar importaciones absolutas tanto como sea posible, por lo que es preferible comenzar a escribir from pkg import string en su código




Además de lo que dijo John B, parece que la configuración de la variable __package__ debería ayudar, en lugar de cambiar __main__ que podría __main__ otras cosas. Pero por lo que pude probar, no funciona completamente como debería.

Tengo el mismo problema y ni PEP 328 ni 366 resuelven el problema por completo, ya que ambos, al final del día, necesitan que el jefe del paquete se incluya en sys.path , por lo que pude entender.

También debería mencionar que no encontré cómo formatear la cadena que debería incluirse en esas variables. ¿Es "package_head.subfolder.module_name" o qué?




Desafortunadamente, este es un hack de sys.path, pero funciona bastante bien.

Encontré este problema con otra capa: ya tenía un módulo del nombre especificado, pero era el módulo equivocado.

lo que quería hacer era lo siguiente (el módulo del que trabajaba era module3):

mymodule\
   __init__.py
   mymodule1\
      __init__.py
      mymodule1_1
   mymodule2\
      __init__.py
      mymodule2_1


import mymodule.mymodule1.mymodule1_1  

Tenga en cuenta que ya he instalado mymodule, pero en mi instalación no tengo "mymodule1"

y obtendría un ImportError porque estaba intentando importar desde mis módulos instalados.

Intenté hacer un sys.path.append, y eso no funcionó. Lo que funcionó fue un sys.path.insert

if __name__ == '__main__':
    sys.path.insert(0, '../..')

¡Qué tipo de truco, pero lo tengo todo para trabajar! Así que tenga en cuenta que, si desea que su decisión anule otras rutas, entonces necesita usar sys.path.insert (0, pathname) para que funcione. Este fue un punto muy frustrante para mí, mucha gente dice que use la función "agregar" a sys.path, pero eso no funciona si ya tiene un módulo definido (me parece muy extraño)




Creo que lo que tienes que preguntarte es:

  • ¿Por qué tengo que hacer esto?
  • ¿La separación de mi paquete está bien hecha?

No conozco el contexto por el que quieres hacerlo de esta manera. Pero para mí, un diseño más limpio sería tener la siguiente estructura de paquetes:

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

Entonces solo tienes que hacer:

from sub12 import mod2



Related