¿Es posible usar dos paquetes de Python con el mismo nombre?

Tengo una pregunta sobre las importaciones. La pregunta puede parecer un poco artificial, pero su propósito es explorar las limitaciones del uso de importaciones absolutas para todas las importaciones en un paquete. PEP8 desalienta en gran medida las importaciones relativas (edición: y la Guía de estilo de Google Python dice que no se deben usar nunca).

Digamos que te dan dos paquetes grandes que tienen el mismo nombre y que ambos usan importaciones absolutas de acuerdo con PEP8:

     / pkg1
         mod1.py (contiene una importación absoluta: 'import pkg1.mod2')
         mod2.py
         ...

     / pkg1
         mod1.py (contiene una importación absoluta: 'import pkg1.mod3')
         mod3.py
         ...

También diga que está trabajando en un proyecto de Python en el que le gustaría usar ambos paquetes. Esto podría surgir, digamos, si desea usar dos versiones del mismo paquete en un proyecto.

¿Hay alguna forma de incorporar ambos paquetes en la jerarquía de su proyecto para que pueda utilizar libremente los módulos de ambos paquetes a lo largo de su proyecto?

Para la solución, es aceptable hacer cosas como usar alias de importación y modificar sys.path temporalmente. Pero no está bien cambiar el contenido de ninguno de los directorios de paquetes.

La respuesta corta es no, Python no acepta dos paquetes con el mismo nombre. (Hay cosas llamadas “paquetes de espacio de nombres” que permiten que un solo paquete se implemente en varios directorios, pero requieren que los paquetes involucrados estén configurados para cooperar entre sí).

La forma en que PEP 8 desalienta las importaciones relativas explícitas es uno de sus consejos más cuestionables, precisamente porque hace que sea más difícil cambiar el nombre de un paquete para evitar conflictos de nombres. Si los dos paquetes utilizan importaciones relativas, puede simplemente cambiar el nombre de uno de ellos o anidarlo dentro de otro paquete y terminar con él.

Los alias de importación no le ayudarán aquí, porque es el nombre que termina en sys.modules que importa, y que usa el nombre del módulo como importado, en lugar del nombre que termina enlazado en el módulo de importación.

Si quisiera volverse realmente exótico, podría escribir su propio importador (consulte PEP 302 y la documentación de importlib 3.x ). Si decides ir tan lejos, puedes hacer casi todo lo que quieras.

Mis pruebas iniciales (en Python 2.6 y 3.1) sugieren que lo siguiente podría funcionar:

 import sys, re import foo as foo1 for k in sys.modules: if re.match(r'foo(\.|$)', k): newk = k.replace('foo', 'foo1', 1) sys.modules[newk] = sys.modules[k] # The following may or may not be a good idea #sys.modules[newk].__name__ = newk del sys.modules[k] sys.path.insert(0, './python') import foo as foo2 for k in sys.modules: if re.match(r'foo(\.|$)', k): newk = k.replace('foo', 'foo2', 1) sys.modules[newk] = sys.modules[k] # The following may or may not be a good idea #sys.modules[newk].__name__ = newk del sys.modules[k] 

Sin embargo, solo probé esto contra paquetes muy simples y solo lo probé por curiosidad. Un problema es que probablemente se rompe la reload . Python no está realmente diseñado para manejar múltiples paquetes con el mismo nombre de nivel superior.

En este punto, voy a decir tentativamente que no es posible en el caso general, aunque es posible en ciertas circunstancias limitadas pero es muy frágil.

En realidad, debe usar los espacios de nombres (paquetes) para separar adecuadamente los módulos que desea utilizar. En su código anterior.

 /pkg1 mod1 - can just import mod2 mod2.py __init__.py /pkg2 mod1 - can just import mod2 mod2.py __init__.py 

Y en el rest de los lugares, debe import pkg1.mod1 o import pkg2.mod1 según sea conveniente.

¿Por qué quieres importar dos versiones diferentes de paquetes en primer lugar? Veo que esa es la fuente de todos tus problemas.

Yo sugeriría reescribir su código y usar el último paquete en su lugar.