Pregunta

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 desde mod2.¿Cómo debería hacerlo?

Lo intenté from ..sub2 import mod2 pero recibo un mensaje "Intento de importación relativa sin paquete".

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


Editar:toda mi __init__.pyActualmente están vacíos.

Editar2:Estoy intentando hacer esto porque sub2 contiene clases que se comparten entre subpaquetes (sub1, subX, etc.).

Editar3:El comportamiento que estoy buscando es el mismo que se describe en PEPE 366 (gracias Juan B)

¿Fue útil?

Solución

Todo el mundo parece querer decirte qué deberías hacer en lugar de simplemente responder la pregunta.

El problema es que estás ejecutando el módulo como '__main__' pasando mod1.py como argumento al intérprete.

De 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 (p. ej.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. PEPE 366 describe el cambio.

Actualizar:Según Nick Coghlan, la alternativa recomendada es ejecutar el módulo dentro del paquete usando el modificador -m.

Otros consejos

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.py hace: import app.package_a.module_a
  3. module_a.py hace import app.package_b.module_b

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

Eso funcionará mientras tengas app en tu PYTHONPATH. main.py podría estar en cualquier lugar entonces.

Entonces escribes un setup.py copiar (instalar) todo el paquete de la aplicación y los subpaquetes en las carpetas de Python del sistema de destino, y main.py para apuntar a las carpetas de scripts del sistema.

Aquí está la solución que funciona para mí:

Hago las importaciones relativas como from ..sub2 import mod2y luego, si quiero correr mod1.py luego voy al directorio principal de app y ejecute el módulo usando el modificador python -m como python -m app.sub1.mod1.

La verdadera razón por la que este problema ocurre con las importaciones relativas es que las importaciones relativas funcionan tomando la __name__ propiedad del módulo.Si el módulo se ejecuta directamente, entonces __name__ se establece 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, 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.

"Guido ve la ejecución de scripts dentro de un paquete como un antipatrón" (rechazadoPEP-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')
def import_path(fullpath):
    """ 
    Import a file with full path specification. Allows one to
    import from anywhere, something __import__ does not do. 
    """
    path, filename = os.path.split(fullpath)
    filename, ext = os.path.splitext(filename)
    sys.path.append(path)
    module = __import__(filename)
    reload(module) # Might be out of date
    del sys.path[-1]
    return module

Estoy usando este fragmento para importar módulos desde rutas, espero que ayude

explicación de nosklo's responder con ejemplos

nota:todo __init__.py Los archivos están vacíos.

main.py
app/ ->
    __init__.py
    package_a/ ->
       __init__.py
       fun_a.py
    package_b/ ->
       __init__.py
       fun_b.py

aplicación/paquete_a/fun_a.py

def print_a():
    print 'This is a function in dir package_a'

aplicación/paquete_b/fun_b.py

from app.package_a.fun_a import print_a
def print_b():
    print 'This is a function in dir package_b'
    print 'going to call a function in dir package_a'
    print '-'*30
    print_a()

principal.py

from app.package_b import fun_b
fun_b.print_b()

si tu corres $ python main.py vuelve:

This is a function in dir package_b
going to call a function in dir package_a
------------------------------
This is a function in dir package_a
  • main.py hace: from app.package_b import fun_b
  • fun_b.py lo hace from app.package_a.fun_a import print_a

entonces archiva en la carpeta package_b archivo usado en la carpeta package_a, que es lo que quieres.¿¿Bien??

Desafortunadamente, esto es un truco de sys.path, pero funciona bastante bien.

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

Lo que quería hacer era lo siguiente (el módulo desde el que estaba trabajando era el módulo 3):

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


import mymodule.mymodule1.mymodule1_1  

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

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

Intenté hacer un sys.path.append y no funcionó.Lo que funcionó fue un sys.path.insertar

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

Es una especie de truco, ¡pero lo hice funcionar!Así que tenga en cuenta que si desea que su decisión anular otros caminos ¡entonces necesitas usar sys.path.insert(0, nombre de ruta) para que funcione!Este fue un punto de fricción muy frustrante para mí, mucha gente dice que se use la función "añadir" a sys.path, pero eso no funciona si ya tienes un módulo definido (me parece un comportamiento muy extraño).

Déjame poner esto aquí para mi propia referencia.Sé que no es un buen código Python, pero necesitaba un script para un proyecto en el que estaba trabajando y quería poner el script en un scripts directorio.

import os.path
import sys
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))

Como dice @EvgeniSergeev en los comentarios del OP, puedes importar código desde un .py archivar en una ubicación arbitraria con:

import imp

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

Esto esta tomado de esta respuesta SO.

Echa un vistazo a http://docs.python.org/whatsnew/2.5.html#pep-328-absolute-and-relative-imports.Podrías hacerlo

from .mod1 import stuff

De Documento de Python,

En Python 2.5, puede cambiar el comportamiento de importación a importaciones absolutas usando un from __future__ import absolute_import directiva.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 sean las predeterminadas, import string siempre encontrará la versión de la biblioteca estándar.Se sugiere que los usuarios comiencen a utilizar importaciones absolutas tanto como sea posible, por lo que es preferible comenzar a escribir from pkg import string en tu código

Descubrí que es más fácil configurar la variable de entorno "PYTHONPATH" en la carpeta superior:

bash$ export PYTHONPATH=/PATH/TO/APP

entonces:

import sub1.func1
#...more import

Por supuesto, PYTHONPATH es "global", pero todavía no me ha causado problemas.

Además de lo que dijo John B, parece establecer el __package__ La variable debería ayudar, en lugar de cambiar. __main__ lo que podría arruinar otras cosas.Pero hasta donde pude probar, no funciona completamente como debería.

Tengo el mismo problema y ni PEP 328 ni 366 solucionan el problema por completo, ya que ambos, al final del día, necesitan que el encabezado del paquete esté incluido en sys.path, hasta donde pude entender.

También debo mencionar que no encontré cómo formatear la cadena que debería ir en esas variables.Lo es "package_head.subfolder.module_name" ¿o que?

Supongamos que corres en el nivel superior, luego en mod1 usar:

import sub2.mod2 

en lugar de

from ..sub2 import mod2
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top