Importación desde la biblioteca incorporada cuando existe un módulo con el mismo nombre

Situación: – Hay un módulo en mi carpeta de proyectos llamado calendario – Me gustaría usar la clase de Calendario incorporada de las bibliotecas de Python – Cuando uso el Calendario de importación de calendario, se queja porque está intentando cargar desde mi módulo.

He hecho algunas búsquedas y parece que no puedo encontrar una solución a mi problema.

  • ¿Cómo acceder a un módulo de biblioteca estándar en Python cuando hay un módulo local con el mismo nombre?
  • http://docs.python.org/whatsnew/2.5.html
  • ¿Cómo evitar escribir el nombre del módulo todo el tiempo al importar un módulo en python?

¿Alguna idea sin tener que renombrar mi módulo?

Related of "Importación desde la biblioteca incorporada cuando existe un módulo con el mismo nombre"

En realidad, resolver esto es bastante fácil, pero la implementación siempre será un poco frágil, ya que depende del mecanismo interno de importación de python y están sujetos a cambios en versiones futuras.

(El siguiente código muestra cómo cargar módulos locales y no locales y cómo pueden coexistir)

def import_non_local(name, custom_name=None): import imp, sys custom_name = custom_name or name f, pathname, desc = imp.find_module(name, sys.path[1:]) module = imp.load_module(custom_name, f, pathname, desc) f.close() return module # Import non-local module, use a custom name to differentiate it from local # This name is only used internally for identifying the module. We decide # the name in the local scope by assigning it to the variable calendar. calendar = import_non_local('calendar','std_calendar') # import local module normally, as calendar_local import calendar as calendar_local print calendar.Calendar print calendar_local 

La mejor solución, si es posible, es evitar nombrar sus módulos con el mismo nombre que la biblioteca estándar o los nombres de módulos integrados.

No es necesario cambiar el nombre de su módulo. Más bien, puede usar absolute_import para cambiar el comportamiento de importación. Por ejemplo, con stem / socket.py importo el módulo de socket de la siguiente manera:

 from __future__ import absolute_import import socket 

Esto solo funciona con Python 2.5 y superior; es un comportamiento habilitador que es el predeterminado en Python 3.0 y superior. Pylint se quejará del código pero es perfectamente válido.

La única forma de resolver este problema es secuestrar la maquinaria de importación interna usted mismo. Esto no es fácil, y lleno de peligros. Debe evitar a toda costa la baliza con forma de grial porque el peligro es demasiado peligroso.

Cambie el nombre de su módulo en su lugar.

Si desea aprender cómo secuestrar la maquinaria de importación interna, aquí es donde iría para averiguar cómo hacer esto:

  • La sección de módulos de importación de la documentación de Python 2.7
  • La sección de módulos de importación de la documentación de Python 3.2
  • PEP 302 – Nuevos ganchos de importación

A veces hay buenas razones para meterse en este peligro. La razón por la que das no está entre ellos. Renombra tu modulo.

Si toma el camino peligroso, un problema que encontrará es que cuando carga un módulo, termina con un ‘nombre oficial’ para que Python pueda evitar tener que analizar el contenido de ese módulo nunca más. Puede encontrar una asignación del ‘nombre oficial’ de un módulo al objeto del módulo en sys.modules .

Esto significa que si import calendar en un lugar, cualquier módulo que se importe se pensará como el módulo con el nombre oficial de calendar y todos los demás bashs de import calendar cualquier otro lugar, incluido en otro código que forma parte de la biblioteca principal de Python, conseguir ese calendario

Podría ser posible diseñar un importador de clientes utilizando el módulo imputil en Python 2.x que hizo que los módulos cargados desde ciertas rutas buscaran los módulos que estaban importando en algo diferente a sys.modules primero o algo así. Pero eso es algo extremadamente delicado, y de todos modos no funcionará en Python 3.x.

Hay una cosa extremadamente fea y horrible que puedes hacer que no implica enganchar el mecanismo de importación. Esto es algo que probablemente no deberías hacer, pero es probable que funcione. Convierte su módulo de calendar en un híbrido del módulo de calendario del sistema y su módulo de calendario. Gracias a Boaz Yaniv por el esqueleto de la función que uso . Ponga esto al comienzo de su archivo calendar.py :

 import sys def copy_in_standard_module_symbols(name, local_module): import imp for i in range(0, 100): random_name = 'random_name_%d' % (i,) if random_name not in sys.modules: break else: random_name = None if random_name is None: raise RuntimeError("Couldn't manufacture an unused module name.") f, pathname, desc = imp.find_module(name, sys.path[1:]) module = imp.load_module(random_name, f, pathname, desc) f.close() del sys.modules[random_name] for key in module.__dict__: if not hasattr(local_module, key): setattr(local_module, key, getattr(module, key)) copy_in_standard_module_symbols('calendar', sys.modules[copy_in_standard_module_symbols.__module__]) 

Me gustaría ofrecer mi versión, que es una combinación de la solución de Boaz Yaniv y Omnifarious. Importará la versión del sistema de un módulo, con dos diferencias principales de las respuestas anteriores:

  • Soporta la notación ‘punto’, por ejemplo. paquete.modulo
  • Es un reemplazo directo de la statement de importación en los módulos del sistema, lo que significa que solo tiene que reemplazar esa línea y, si ya se están realizando llamadas al módulo, funcionarán como están

Ponga esto en un lugar accesible para que pueda llamarlo (tengo el mío en mi archivo __init__.py):

 class SysModule(object): pass def import_non_local(name, local_module=None, path=None, full_name=None, accessor=SysModule()): import imp, sys, os path = path or sys.path[1:] if isinstance(path, basestring): path = [path] if '.' in name: package_name = name.split('.')[0] f, pathname, desc = imp.find_module(package_name, path) if pathname not in __path__: __path__.insert(0, pathname) imp.load_module(package_name, f, pathname, desc) v = import_non_local('.'.join(name.split('.')[1:]), None, pathname, name, SysModule()) setattr(accessor, package_name, v) if local_module: for key in accessor.__dict__.keys(): setattr(local_module, key, getattr(accessor, key)) return accessor try: f, pathname, desc = imp.find_module(name, path) if pathname not in __path__: __path__.insert(0, pathname) module = imp.load_module(name, f, pathname, desc) setattr(accessor, name, module) if local_module: for key in accessor.__dict__.keys(): setattr(local_module, key, getattr(accessor, key)) return module return accessor finally: try: if f: f.close() except: pass 

Ejemplo

Quería importar mysql.connection, pero ya tenía un paquete local llamado mysql (las utilidades oficiales de mysql). Así que para obtener el conector del paquete mysql del sistema, reemplacé esto:

 import mysql.connector 

Con este:

 import sys from mysql.utilities import import_non_local # where I put the above function (mysql/utilities/__init__.py) import_non_local('mysql.connector', sys.modules[__name__]) 

Resultado

 # This unmodified line further down in the file now works just fine because mysql.connector has actually become part of the namespace self.db_conn = mysql.connector.connect(**parameters) 

Cambiar la ruta de importación:

 import sys save_path = sys.path[:] sys.path.remove('') import calendar sys.path = save_path