您始终可以使用一些技巧,例如导入模块然后从 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
is 在 python3.3+ 中已弃用 https://docs.python.org/3/library/imp.html#imp.load_module,并建议使用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 调用的第一个参数输入的两个名称。看看文档 http://docs.python.org/library/imp.html了解详情。
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”字符串两次,这就是 import 语句的工作原理;但事实上,这两个字符串有两个不同的原因。
我们将其传递给 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'