Ответ 1
Вы всегда можете делать трюки, например, импортировать модуль, а затем удалять его из sys.modules или пытаться скопировать модуль. Тем не менее, Python уже предоставляет то, что вы хотите в своей стандартной библиотеке.
import imp # Standard module to do such things you want to.
# We can import any module including standard ones:
os1=imp.load_module('os1', *imp.find_module('os'))
# Here is another one:
os2=imp.load_module('os2', *imp.find_module('os'))
# This returns True:
id(os1)!=id(os2)
Python3.3 +
imp.load_module
устарел в python3.3 + и рекомендует использоватьimportlib
#!/usr/bin/env python3 import sys import importlib.util SPEC_OS = importlib.util.find_spec('os') os1 = importlib.util.module_from_spec(SPEC_OS) SPEC_OS.loader.exec_module(os1) sys.modules['os1'] = os1 os2 = importlib.util.module_from_spec(SPEC_OS) SPEC_OS.loader.exec_module(os2) sys.modules['os2'] = os2 del SPEC_OS assert os1 is not os2, \ "Module `os` instancing failed"
Здесь мы импортируем тот же модуль дважды, но как полностью разные объекты модуля. Если вы проверите sys.modules, вы можете увидеть два имени, которые вы ввели в качестве первых параметров для вызовов load_module. Подробнее см. документация.
UPDATE:
Чтобы сделать основное отличие этого подхода очевидным, я хочу сделать это более понятным: если вы импортируете один и тот же модуль таким образом, вы будете иметь обе версии, доступные глобально для каждого другого модуля, который вы импортируете во время выполнения, что и есть то, что как я понял.
Ниже приведен еще один пример, чтобы подчеркнуть этот момент.
Эти два утверждения делают одно и то же:
import my_socket_module as socket_imported
socket_imported = imp.load_module('my_socket_module',
*imp.find_module('my_socket_module')
)
Во второй строке мы повторяем строку 'my_socket_module' дважды, и так действует операция импорта; но эти две строки фактически используются по двум причинам.
Второе вхождение, когда мы передали его find_module, используется как имя файла, которое будет найдено в системе. Первое вхождение строки при ее передаче в метод load_module используется как общесистемный идентификатор загруженного модуля.
Таким образом, мы можем использовать разные имена для них, что означает, что мы можем заставить его работать точно так же, как мы скопировали исходный файл python для модуля и загрузили его.
socket = imp.load_module('socket_original', *imp.find_module('my_socket_module'))
socket_monkey = imp.load_module('socket_patched',*imp.find_module('my_socket_module'))
def alternative_implementation(blah, blah):
return 'Happiness'
socket_monkey.original_function = alternative_implementation
import my_sub_module
Затем в my_sub_module я могу импортировать 'socket_patched', который не существует в системе! Здесь мы находимся в my_sub_module.py.
import socket_patched
socket_patched.original_function('foo', 'bar')
# This call brings us 'Happiness'