Importación relativa absoluta vs explícita del módulo de Python

85

Me pregunto cuál es la forma preferida de importar paquetes en una aplicación Python. Tengo una estructura de paquete como esta:

project.app1.models
project.app1.views
project.app2.models

project.app1.views importaciones project.app1.models y project.app2.models. Hay dos formas de hacer esto que se me ocurren.

Con importaciones absolutas:

import A.A
import A.B.B

o con importaciones relativas explícitas, como se introdujo en Python 2.5 con PEP 328 :

# explicit relative
from .. import A
from . import B

¿Cuál es la forma más pitónica de hacer esto?

Daniel Hepper
fuente
los ejemplos "relativos explícitos" son errores de sintaxis. Las importaciones relativas deben estar en el formulario from _ import ..., por lo que sus ejemplos serían from .. import Ayfrom . import B
MestreLion
@MestreLion ¡Buen partido, tienes toda la razón! Actualicé mi pregunta de import ..Aa from .. import A. Es notable que solo pasaron 9 años hasta que alguien se dio cuenta;)
Daniel Hepper

Respuestas:

52

Importaciones absolutas. Desde PEP 8:

Se desaconsejan en gran medida las importaciones relativas para las importaciones dentro del paquete. Utilice siempre la ruta absoluta del paquete para todas las importaciones. Incluso ahora que PEP 328 [7] está completamente implementado en Python 2.5, su estilo de importaciones relativas explícitas se desaconseja activamente; las importaciones absolutas son más portátiles y normalmente más legibles.

Las importaciones relativas explícitas son una buena característica del lenguaje (supongo), pero no son tan explícitas como las importaciones absolutas. La forma más legible es:

import A.A
import A.B.B

especialmente si importa varios espacios de nombres diferentes. Si observa algunos proyectos / tutoriales bien redactados que incluyen importaciones desde dentro de los paquetes, generalmente siguen este estilo.

Las pocas pulsaciones de teclas adicionales que tome para ser más explícito ahorrarán a otros (y tal vez a usted) mucho tiempo en el futuro cuando intenten averiguar su espacio de nombres (especialmente si migra a 3.x, en el que parte del paquete los nombres han cambiado).

Rafe Kettler
fuente
@Rafe, "mira algunos proyectos bien escritos ..." ¿alguna sugerencia?
denis
@Denis: Rietveld es el proyecto del propio Guido van Rossum, así que imagino que sería un buen lugar para buscar ( code.google.com/p/rietveld ). La biblioteca estándar de Python no es tan buena, gran parte de ese código no sigue las convenciones.
Rafe Kettler
68
@Rafe: esa parte del PEP-8 está desactualizada, según Guido. mail.python.org/pipermail/python-dev/2010-October/104476.html
Brandon Rhodes
12
Esa declaración ya no está en PEP-8 ahora. Ahora establece que se recomiendan las importaciones absolutas, pero las importaciones relativas son una alternativa aceptable.
dano
6
El problema que tengo con las importaciones absolutas es cuando uso un paquete dentro de otro paquete. En mi caso, está presente como un submódulo de git. En este caso, aunque puedo importar el paquete de nivel superior, los paquetes por debajo de este no se pueden importar porque no encuentran sus propios módulos con importaciones absolutas. Mientras que si utilizo importaciones relativas en este nivel inferior, todo simplemente funciona.
davidA
122

Las importaciones relativas de Python ya no se desaconsejan enérgicamente, pero en ese caso se recomienda encarecidamente el uso de absolute_import.

Consulte esta discusión citando al propio Guido:

"¿No es esto mayormente histórico? Hasta que se implementó la nueva sintaxis de importación relativa, había varios problemas con las importaciones relativas. La solución a corto plazo fue recomendar no usarlas. La solución a largo plazo fue implementar una sintaxis inequívoca. Ahora es hora de retirar la anti-recomendación. Por supuesto, sin exagerar, todavía encuentro un gusto adquirido, pero tienen su lugar ".

El OP vincula correctamente el PEP 328 que dice:

Se presentaron varios casos de uso, el más importante de los cuales es poder reorganizar la estructura de paquetes grandes sin tener que editar subpaquetes. Además, un módulo dentro de un paquete no se puede importar fácilmente sin importaciones relativas.

También vea la pregunta casi duplicada Cuándo o por qué usar importaciones relativas en Python

Por supuesto que sigue en pie por cuestión de gustos. Si bien es más fácil mover el código con importaciones relativas, eso también podría romper cosas inesperadamente; y cambiar el nombre de las importaciones no es tan difícil.

Para forzar el nuevo comportamiento de PEP 328 use:

from __future__ import absolute_import

En este caso, la importación relativa implícita ya no será posible (por ejemplo, import localfileya no funcionará, solo from . import localfile). Para un comportamiento limpio y a prueba de futuro, se recomienda utilizar absolute_import.

Una advertencia importante es que debido a PEP 338 y PEP 366 , las importaciones relativas requieren que el archivo python se importe como un módulo; no puede ejecutar un file.py que tenga una importación relativa o obtendrá un archivo ValueError: Attempted relative import in non-package.

Esta limitación debe tenerse en cuenta al evaluar el mejor enfoque. Guido está en contra de ejecutar scripts desde un módulo en cualquier caso:

Soy -1 en esto y en cualquier otro giro propuesto de la maquinaria __ principal__. El único caso de uso parece ser ejecutar scripts que viven dentro del directorio de un módulo, lo que siempre he visto como un antipatrón. Para hacerme cambiar de opinión, tendrías que convencerme de que no lo es.

Se pueden encontrar discusiones exhaustivas sobre el tema en SO; re. Python 3 esto es bastante completo:

Stefano
fuente
9
¿Guido escribió eso en 2010 y todavía está en el PEP? ¿Cómo podemos confiar en las PEP si están tan desactualizadas?
Jabba
2
Las PEP son como las enmiendas estadounidenses en el sentido de que se pueden enmendar cosas. También hay muchos PEPS rechazados. Los PEP son propuestas. Pueden aceptarse, rechazarse o volverse obsoletos, lo que a menudo significa una nueva PEP. PEP 8 es una guía de estilo que puede modificarse en su lugar.
CppLearner
2
Estoy confundido acerca de la parte "un módulo dentro de un paquete no se puede importar fácilmente ...". Nunca antes había oído hablar de la importación de módulos por sí mismos.
matiascelasco
2
Un posible ejemplo @matiascelasco: si tiene foo / bar.py y foo / baz.py pero también baz.py en otro lugar. Si desea importar foo.baz desde bar, es posible que desee estar seguro de lo que está importando, por ejemplo. import .bazSin embargo, esta es solo una simplista de muchas situaciones similares descritas en el PEP.
Stefano
Su respuesta no distingue claramente el cambio al permitirlos. Las importaciones relativas implícitas nunca deben usarse, pero está bien usar importaciones relativas explícitas. El relativo implícito se ha eliminado de Python3.
ninMonkey
33

Las importaciones relativas no solo le permiten cambiar el nombre de su paquete más tarde sin cambiar docenas de importaciones internas, sino que también he tenido éxito con ellas para resolver ciertos problemas que involucran cosas como importaciones circulares o paquetes de espacio de nombres, porque no envían Python "de vuelta al top "para iniciar la búsqueda del siguiente módulo desde el espacio de nombres de nivel superior.

Brandon Rhodes
fuente
4
Este es el estilo desaconsejado según la guía de estilo de Python. Se nublan severamente la legibilidad y no valen la "comodidad" percibida a la que alude. Si necesita utilizar importaciones relativas para resolver un problema, lo está haciendo mal.
Rafe Kettler
14
Tenga en cuenta su comentario (Brandon Rhodes) sobre la otra respuesta, con un enlace que muestra que ya no está desanimado.
Jon Coombs
1
@RafeKettler, ¿puede explicar cómo usaría las importaciones absolutas en un paquete que está incluido dentro de otro paquete? Las importaciones absolutas fallarán dentro del paquete interno porque no conocen el nuevo nivel superior. Las importaciones relativas siguen funcionando. Probablemente se podría argumentar que el paquete no debería estar anidado dentro de otro en primer lugar, pero parte del código está destinado a ser reutilizable y esto sucede con frecuencia. Una gran cantidad de código reutilizado no se empaqueta para el público y, por lo tanto, no se proporciona como un paquete separado, por lo que los métodos ad-hoc como la importación / submódulos de VCS terminan usándose en su lugar
DavidA
3
@meowsqueak Estoy de acuerdo, algunos paquetes no son fáciles de instalar (no están en pip, no quieres usarlos python setup.py installo python setup.py developpor alguna razón), en esos casos bifurco el código fuente y lo agrego como un submódulo git. Cuando esos paquetes utilizan importaciones absolutas en su propio nombre de paquete, sus importaciones fallan. La única solución es utilizar importaciones relativas explícitas. Eso es lo que debería animarse, creo.
CMCDragonkai