Situation: - Il y a un module dans mon dossier projet_folder appelé calendar - J'aimerais utiliser la classe de calendrier intégrée à partir des bibliothèques Python - - Lorsque j'utilise un calendrier à partir de calendrier, il se plaint parce qu'il essaie charger de mon module.
J'ai fait quelques recherches et je n'arrive pas à trouver une solution à mon problème.
Des idées sans avoir à renommer mon module?
En fait, résoudre ce problème est plutôt facile, mais la mise en œuvre restera toujours un peu fragile, car cela dépend des éléments internes du mécanisme d'importation python et ils sont susceptibles de changer dans les versions futures.
(le code suivant montre comment charger des modules locaux et non locaux et comment ils peuvent coexister)
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 meilleure solution, dans la mesure du possible, consiste à éviter de nommer vos modules avec le même nom que les noms de modules de bibliothèque standard ou intégrés.
Changer le nom de votre module n'est pas nécessaire. Au lieu de cela, vous pouvez utiliser absolute_import pour modifier le comportement d'importation. Par exemple avec stem/socket.py J'importe le module de socket comme suit:
from __future__ import absolute_import
import socket
Cela ne fonctionne qu'avec Python 2.5 et plus; c'est un comportement qui est le comportement par défaut de Python 3.0 et supérieur. Pylint va se plaindre du code mais il est parfaitement valide .
Le seul moyen de résoudre ce problème est de détourner vous-même la machine d'importation interne. Ce n'est pas facile, et périlleux. Vous devez éviter à tout prix le phare en forme de graal car le péril est trop périlleux.
Renommez votre module à la place.
Si vous souhaitez apprendre à détourner les machines d'importation internes, voici comment procéder:
Il y a parfois de bonnes raisons d'entrer dans ce péril. La raison pour laquelle vous donnez n'est pas parmi eux. Renommez votre module.
Si vous prenez le chemin périlleux, un problème que vous rencontrerez est que lorsque vous chargez un module, il se termine par un 'nom officiel' de sorte que Python peut éviter de devoir analyser le contenu de ce fichier.) module. Un mappage du 'nom officiel' d’un module sur son objet module se trouve dans sys.modules
.
Cela signifie que si vous import calendar
à un endroit, tout module importé sera considéré comme le module portant le nom officiel calendar
et toutes les autres tentatives visant à import calendar
n'importe où ailleurs, y compris dans un code qui fait partie de la bibliothèque principale Python), obtiendra ce calendrier.
Il serait peut-être possible de concevoir un importateur client à l'aide du module imputil dans Python 2.x à l'origine du chargement des modules à partir de certains chemins pour rechercher les modules qu'ils importaient dans autre chose que sys.modules
premier ou quelque chose comme ça. Mais c'est une chose extrêmement poilue à faire, et cela ne fonctionnera pas dans Python 3.x de toute façon.
Vous pouvez faire une chose extrêmement laide et horrible qui ne consiste pas à accrocher le mécanisme d'importation. C'est quelque chose que vous ne devriez probablement pas faire, mais cela fonctionnera probablement. Il transforme votre module calendar
en un hybride du module calendrier système et de votre module calendrier. Merci à Boaz Yaniv pour le squelette de la fonction que j'utilise . Mettez ceci au début de votre calendar.py
fichier:
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__])
J'aimerais proposer ma version, qui combine les solutions de Boaz Yaniv et d'Omnifarious. Il importera la version système d'un module, avec deux différences principales par rapport aux réponses précédentes:
Mettez ceci quelque part accessible pour que vous puissiez l'appeler (j'ai le mien dans mon fichier __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
Je voulais importer mysql.connection, mais j'avais déjà un paquet local appelé mysql (les utilitaires officiels de mysql). Donc, pour obtenir le connecteur du paquet mysql du système, j'ai remplacé ceci:
import mysql.connector
Avec ça:
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__])
# 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)