lista - modulos python
Importación desde la biblioteca interna cuando existe un módulo con el mismo nombre (5)
Cambiar la ruta de importación:
import sys
save_path = sys.path[:]
sys.path.remove('''')
import calendar
sys.path = save_path
Situación: - Hay un módulo en mi project_folder llamado calendar - Me gustaría utilizar la clase incorporada de Calendar de las bibliotecas de Python - Cuando lo uso desde Calendar import Calendar 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 cambiar el nombre de mi módulo?
En realidad, resolver esto es bastante fácil, pero la implementación siempre será un poco frágil, ya que depende de las partes internas del mecanismo de importación de python y están sujetas a cambios en futuras versiones.
(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 los módulos integrados.
La única forma de resolver este problema es secuestrar la maquinaria interna de importación usted mismo. Esto no es fácil y está lleno de peligros. Debe evitar a toda costa el faro en forma de grial porque el peligro es demasiado peligroso.
Cambie el nombre de su módulo en su lugar.
Si desea aprender a secuestrar la maquinaria interna de importación, aquí es donde debería averiguar cómo hacer esto:
- La sección Importar módulos de la documentación de Python 2.7
- La sección 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 entrar en este peligro. La razón por la que das no está entre ellos. Cambia el nombre de tu módulo.
Si tomas el camino peligroso, un problema que encontrarás es que cuando cargas un módulo termina con un ''nombre oficial'' para que Python pueda evitar tener que volver a analizar los contenidos de ese módulo. En sys.modules
se puede encontrar un mapeo del "nombre oficial" de un módulo al objeto del módulo en sys.modules
.
Esto significa que si import calendar
en un lugar, se considerará que el módulo importado es el módulo con el calendar
oficial y todos los demás intentos de import calendar
cualquier otro lugar, incluso en otro código que forma parte de la biblioteca principal de Python. obtener ese calendario
Podría ser posible diseñar un importador de clientes utilizando el módulo imputil en Python 2.x que causó que los módulos cargados desde ciertas rutas sys.modules
primero los módulos que estaban importando en algo que no sea sys.modules
o algo así. Pero eso es algo extremadamente peludo de hacer, y de todos modos no funcionará en Python 3.x.
Hay algo extremadamente feo y horrible que puedes hacer que no implica enganchar el mecanismo de importación. Esto es algo que probablemente no debería hacer, pero probablemente funcionará. 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 por el esqueleto de la función que uso . Pon esto al comienzo de tu 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:
- Admite la notación ''punto'', p. Ej. paquete.modulo
- Es un reemplazo directo para la declaración 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 tal cual.
Ponga esto en algún 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 tenía un paquete local que ya se llamaba mysql (las utilidades oficiales de mysql). Entonces, para obtener el conector del paquete mysql del sistema, lo reemplacé:
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)
No es necesario cambiar el nombre de su módulo. Por el contrario, 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; su comportamiento de habilitación es el predeterminado en Python 3.0 y superior. Pylint se quejará del código, pero es perfectamente válido.