#python #python-2.7 #import #python-importlib
#python #python-2.7 #импорт #python-importlib
Вопрос:
У меня есть пакет python с именем foo
, который я использую при импорте:
import foo.conf
from foo.core import Something
Теперь мне нужно переименовать foo
модуль во что-то другое, скажем bar
, поэтому я хочу сделать:
import bar.conf
from bar.core import Something
но я хочу поддерживать обратную совместимость с существующим кодом, поэтому импорт old ( foo.
) должен работать так же хорошо и выполнять то же самое bar.
, что и импорт.
Как это можно сделать в python 2.7?
Ответ №1:
Это заставляет вас сохранять foo
каталог, но я думаю, что это лучший способ заставить это работать.
Настройка каталога:
bar
├── __init__.py
└── baz.py
foo
└── __init__.py
foo_bar.py
bar/__init__.py
пусто.
bar/baz.py
: worked = True
foo/__init__.py
:
import sys
# make sure bar is in sys.modules
import bar
# link this module to bar
sys.modules[__name__] = sys.modules['bar']
# Or simply
sys.modules[__name__] = __import__('bar')
foo_bar.py
:
import foo.baz
assert(hasattr(foo, 'baz') and hasattr(foo.baz, 'worked'))
assert(foo.baz.worked)
import bar
assert(foo is bar)
Комментарии:
1. Это не работает должным образом. Если модуль имеет подмодули, то они не совпадают.
2. Для надежного решения, включающего подмодули, вам также необходимо явно добавить псевдонимы для каждого подмодуля в sys.modules . Это работает (я пробовал это на Python 3.6 / 3.7, так что даже в последних версиях) и успешно устраняет тонкую ошибку, из-за которой вы получаете несколько экземпляров одного и того же модуля с разными именами (что может вызвать кошмары, если у вас есть статическое состояние для каждого модуля или проверки isinstance (), которые путаютсяесли существует несколько версий одного и того же класса с разными именами). Работает лучше, чем подход MetaPathFinder.
3. Интересно, есть ли какое-либо решение, которое не предполагает создания отдельного
foo
каталога ().
Ответ №2:
Вы имеете в виду что-то подобное?
import foo as bar
вы можете использовать ярлыки для импорта модулей
Нравится:
from numpy import array as arr
in: arr([1,2,3])
out: array([1, 2, 3])
и вы также можете использовать более одного псевдонима одновременно
from numpy import array as foo
in: foo([1,2,3])
out: array([1, 2, 3])
если ваш foo
класс, вы можете сделать:
bar=foo()
и вызовите его подфункцию
с помощью:
bar.conf()
Это вам помогает?
Комментарии:
1. Нет, я не хочу изменять существующие обычаи. Я хочу
import foo
работать точно так же, какimport bar
.2. Использование псевдонима, т.Е.
as
Дал мнеsubmodule not found error
.
Ответ №3:
Этот ответ работает с подмодулями:
import sys
import os
from importlib.abc import MetaPathFinder, Loader
import importlib
from MainModule.SubModule import *
class MyLoader(Loader):
def module_repr(self, module):
return repr(module)
def load_module(self, fullname):
old_name = fullname
names = fullname.split(".")
names[1] = "SubModule"
fullname = ".".join(names)
module = importlib.import_module(fullname)
sys.modules[old_name] = module
return module
class MyImport(MetaPathFinder):
def find_module(self, fullname, path=None):
names = fullname.split(".")
if len(names) >= 2 and names[0] == "Module" and names[1] == "LegacySubModule":
return MyLoader()
sys.meta_path.append(MyImport())
Комментарии:
1. Хотя этот пример немного надуманный, он действительно показывает, как переопределить импорт, и просто лучше, чем вся
importlib.abc
неприятная документация. Спасибо!2. У меня возникла проблема, когда я попытался загрузить pickle, для которого требовался модуль, реорганизованный под новым именем. Этот ответ отлично сработал, чтобы автоматически переназначить старый импорт на новый