¿Qué hay de malo con las importaciones relativas en Python?

89

Recientemente actualicé versiones de pylint , un popular corrector de estilo Python.

Se ha vuelto balístico a lo largo de mi código, señalando lugares donde importo módulos en el mismo paquete, sin especificar la ruta completa del paquete.

El nuevo mensaje de error es W0403.

W0403: Importación relativa% r, debe ser% r

Se utiliza cuando se detecta una importación relativa al directorio del paquete.


Ejemplo

Por ejemplo, si mis paquetes están estructurados así:

/cake
  /__init__.py
  /icing.py
  /sponge.py
/drink

y en el paquete de esponja escribo:

import icing

en lugar de

import cake.icing

Obtendré este error.


Si bien entiendo que no todos los mensajes de Pylint son de igual importancia, y no tengo miedo de descartarlos, no entiendo por qué esa práctica se considera una mala idea.

Esperaba que alguien pudiera explicar las trampas, para poder mejorar mi estilo de codificación en lugar de (como lo planeo hacer actualmente) desactivar esta advertencia aparentemente espuria.

Pensamiento extraño
fuente

Respuestas:

98

El problema import icinges que no sabes si es una importación absoluta o una importación relativa. icingpodría un módulo en la ruta de Python, o un paquete en el módulo actual. Esto es bastante molesto cuando un paquete local tiene el mismo nombre que un paquete de biblioteca estándar de Python.

Puede hacer lo from __future__ import absolute_importque desactiva las importaciones relativas implícitas por completo. Se describe, incluso con esta justificación sobre la ambigüedad, en PEP 328 . Creo que Python 3000 tiene importaciones relativas implícitas desactivadas por completo.

Todavía puede hacer importaciones relativas, pero debe hacerlas explícitamente, así:

from . import icing
Winston Ewert
fuente
2
+1 especialmente para la solución de compromiso, que es probablemente el camino que debo seguir.
Pensamiento extraño
2
Tenga en cuenta que también puede hacerlo en import .icinglugar defrom . import icing
Jack
11
@ Jack en realidad no creo que puedas. De esta parte de PEP328 : Las importaciones relativas siempre deben usarse from <> import; import <>Siempre es absoluto. Por supuesto, las importaciones absolutas pueden usarse from <> importomitiendo los puntos principales. La razón import .fooestá prohibida porque después de import XXX.YYY.ZZZeso XXX.YYY.ZZZse puede usar en una expresión. Pero .moduleYno es utilizable en una expresión.
A.Wan
47

Hay algunas buenas razones:

  1. Las importaciones relativas se rompen fácilmente cuando mueve un módulo.

    Imagine que tiene un foo.bar, a foo.bazy un bazmódulo en su paquete. foo.barimportaciones foo.baz, pero utilizando una importación relativa.

    Ahora bien, si se va a mover foo.bara bar, su módulo de repente está importando una diferente baz!

  2. Las importaciones relativas son ambiguas. Incluso sin moverse por el barmódulo en el ejemplo anterior, un nuevo desarrollador que llegue a su proyecto podría ser perdonado por no darse cuenta de que bazrealmente es en foo.bazlugar del bazpaquete de nivel raíz .

    Las importaciones absolutas hacen explícito qué módulo se está utilizando. Y como import thispredica, explícito es mejor que implícito.

  3. Python 3 ha deshabilitado las importaciones relativas implícitas por completo; las importaciones ahora siempre se interpretan como absolutas, lo que significa que en el ejemplo anterior import bazsiempre se importará el módulo de nivel superior. Deberá utilizar la sintaxis de importación explícita en su lugar ( from . import baz).

    Transmitir el ejemplo de Python 2 a 3 generaría problemas inesperados, ya que el uso de importaciones absolutas ahora hará que su código esté preparado para el futuro.

Martijn Pieters
fuente
11
+1 para # 2 y # 3. Pero el n. ° 1 debe compensarse con lo que sucede cuando se mueve todo el directorio (por ejemplo, se baja un nivel).
Pensamiento extraño