Uso de absolute_import y manejo de conflictos de nombre de módulo relativos en Python

Realmente espero que este sea un caso simple en el que no entiendo bien los complejos mecanismos de importación de Python2. Tengo la siguiente configuración:

$> ls -ltr pypackage1 total 3 -rw-r--r-- 1 pelson pelson 0 Aug 17 19:20 io.py -rw-r--r-- 1 pelson pelson 0 Aug 17 19:20 __init__.py -rw-r--r-- 1 pelson pelson 57 Aug 17 19:22 code.py $> cat pypackage1/code.py from __future__ import absolute_import import zipfile 

es decir, no tengo más que un paquete de código auxiliar con un __init__.py e io.py vacío, y un archivo code.py 2 líneas.

Puedo importar pypackage1 :

 $> python -c "import pypackage1.code" 

Pero no puedo ejecutar el archivo code.py :

 $> python pypackage1/code.py Traceback (most recent call last): File "pypackage1/code.py", line 3, in  import zipfile File "python2.7/zipfile.py", line 462, in  class ZipExtFile(io.BufferedIOBase): AttributeError: 'module' object has no attribute 'BufferedIOBase' 

Claramente, el problema tiene que ver con el módulo zipfile que recoge mi módulo de io relativo sobre el módulo de io incorporado, pero pensé que mi problema from __future__ import absolute_import lo habría solucionado.

Gracias de antemano por cualquier ayuda,

Ese es el comportamiento correcto. Si desea corregir el error, simplemente no ejecute desde dentro del paquete.

Cuando ejecutas un script que está dentro del paquete, Python no interpreta ese directorio como un paquete, por lo que agrega el directorio de trabajo a PYTHONPATH . Es por eso que el módulo io importado por el módulo zipfile es su módulo io y no el que está dentro de la biblioteca estándar.

Recomiendo crear un script de inicio simple fuera de su paquete (o en una carpeta bin/scripts ), e iniciarlo. Este script puede contener simplemente algo como:

 from pypackage1 import code code.main() 

Una alternativa a esto es decirle al intérprete de python que el archivo que desea ejecutar es parte de un módulo. Puedes hacer esto usando la opción de línea de comando -m . En tu caso deberías hacer:

 python -m pypackage1.code 

Tenga en cuenta que el argumento de -m debe ser el nombre del módulo , no el nombre del archivo.

Una solución sería colocar from __future__ import absolute_import en el módulo zipfile.py . Aunque su módulo está utilizando la importación absoluta, el módulo zipfile no lo está.

Otra opción es no ejecutar desde el directorio de su paquete. Probablemente no debería estar ejecutando el intérprete desde el directorio del paquete.

Estructura de archivos:

 test.py mylib/__init__.py mylib/__collections.py mylib/collections.py mylib/mymod.py 

Esta solución permite:

  • test.py para invocar tanto __builtin __. colecciones como mylib.collections
  • mymod.py para invocar lo anterior, tanto cuando se ejecuta como parte de la biblioteca como cuando se ejecuta de forma independiente (por ejemplo, para el código de prueba)

En test.py:

 from collections import deque from mylib.collections import mydict 

En mylib / __ init__.py:

 from __future__ import absolute_import from . import collections from . import mymod 

En mylib / __ collections.py:

 class MyDict (dict): pass 

En mylib / collections.py:

 from __collections import * 

En mylib / mymod.py:

 from __future__ import absolute_import from collections import deque try: # Module running as part of mylib from .collections import MyDict except ValueError: # Module running independently from __collections import MyDict 

Lo anterior funciona con Python> = 2.5. Python 3 no necesita las líneas ‘de __future__ importar absolute_import’.