Импорт из встроенной библиотеки при наличии модуля с таким же именем
Ситуация:
- В моей папке project_folder называется модуль
- Я хотел бы использовать встроенный класс Calendar из библиотек Python
- Когда я использую календарь календаря импорта, он жалуется, потому что пытается загрузить из моего модуля.
Я сделал несколько поисков, и я не могу найти решение моей проблемы.
Любые идеи без переименования моего модуля?
Ответы
Ответ 1
На самом деле, решение этого довольно просто, но реализация всегда будет немного хрупкой, поскольку она зависит от внутренних механизмов механизма импорта python, и они могут быть изменены в будущих версиях.
(следующий код показывает, как загружать как локальные, так и нелокальные модули и то, как они могут сосуществовать)
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
Лучшее решение, если это возможно, состоит в том, чтобы не называть ваши модули с тем же именем, что и имена стандартной библиотеки или встроенных модулей.
Ответ 2
Изменение имени вашего модуля не требуется. Скорее вы можете использовать absolute_import, чтобы изменить поведение импорта. Например, stem/socket.py Я импортирую модуль сокета следующим образом:
from __future__ import absolute_import
import socket
Это работает только с Python 2.5 и выше; это позволяет поведение, которое по умолчанию используется в Python 3.0 и выше. Пилинт будет жаловаться на код, но он совершенно прав.
Ответ 3
Единственный способ решить эту проблему - захватить внутреннее импортное оборудование самостоятельно. Это непросто и чревато опасностью. Вы должны избегать огненного маяка с гравием любой ценой, потому что опасность слишком опасна.
Вместо этого переименуйте свой модуль.
Если вы хотите узнать, как захватить внутреннюю машину импорта, вот где вы можете узнать, как это сделать:
Иногда есть веские причины, чтобы попасть в эту опасность. Причина, по которой вы даете, не среди них. Переименуйте свой модуль.
Если вы возьмете опасный путь, одна из проблем, с которыми вы столкнетесь, заключается в том, что при загрузке модуля он заканчивается "официальным именем", поэтому Python может избежать необходимости анализировать содержимое этого модуля заново. Отображение "официального имени" модуля самому объекту модуля можно найти в sys.modules
.
Это означает, что если вы import calendar
в одном месте, любой импортируемый модуль будет считаться модулем с официальным именем calendar
и всеми другими попытками import calendar
в другом месте, в том числе в другом коде, из основной библиотеки Python, получит этот календарь.
Возможно, можно спроектировать импортера клиента, используя модуль imputil в Python 2.x, из-за чего модули, загруженные с определенных путей, выглядят сначала импортировали модули, которые они импортировали в чем-то, кроме sys.modules
, или что-то в этом роде. Но это очень волосатое дело, и в любом случае это не будет работать в Python 3.x.
Существует очень уродливая и ужасная вещь, которую вы можете сделать, что не связано с подключением механизма импорта. Это то, чего вы, вероятно, не должны делать, но это, скорее всего, будет работать. Он превращает ваш модуль calendar
в гибрид системного календарного модуля и вашего модуля календаря. Благодаря Boaz Yaniv для скелета функции, которую я использую. Поместите это в начало вашего файла 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__])
Ответ 4
Я хотел бы предложить свою версию, которая представляет собой комбинацию решения Boaz Yaniv и Omnifarious. Он будет импортировать системную версию модуля с двумя основными отличиями от предыдущих ответов:
- Поддерживает "точную" нотацию, например. package.module
- Является заменой замены для оператора импорта на системных модулях, то есть вам просто нужно заменить эту одну строку, и если уже есть вызовы, выполняемые в модуле, они будут работать как-есть
Поместите это где-нибудь доступным, чтобы вы могли его вызвать (у меня есть мой файл __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
Пример
Я хотел импортировать mysql.connection, но у меня был локальный пакет, уже называемый mysql (официальные утилиты mysql). Поэтому, чтобы получить соединитель из системного пакета mysql, я заменил это:
import mysql.connector
При этом:
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)
Ответ 5
Измените путь импорта:
import sys
save_path = sys.path[:]
sys.path.remove('')
import calendar
sys.path = save_path