当一个模块被导入两次时会发生啥?
Posted
技术标签:
【中文标题】当一个模块被导入两次时会发生啥?【英文标题】:What happens when a module is imported twice?当一个模块被导入两次时会发生什么? 【发布时间】:2013-10-05 07:44:11 【问题描述】:我有一个疑问,我想澄清一下。
考虑以下名为 ex_1.py
的模块:
print("Hello, I'm ex_1")
def greet(name):
print("Hello, "+name+" nice to meet you! ")
现在考虑另一个名为 1_client_ex_1.py
的文件,它将导入 ex_1.py
模块。
import ex_1.py
现在当我执行这个文件时,我得到的输出是:
Hello, I'm ex_1
正如预期的那样。
但是当我将1_client_ex_1.py
改为:
import ex_1.py
import ex_1.py
并执行它,它仍然只打印一次Hello, I'm ex_1
。不应该打印两次吗?
【问题讨论】:
行为正确 【参考方案1】:没什么,如果一个模块已经被导入,它就不会再次加载。
您将简单地获得对已导入模块的引用(它将来自sys.modules
)。
要获取已经导入的模块列表,可以查找sys.modules.keys()
(注意urllib
这里导入了很多个其他模块):
>>> import sys
>>> print len(sys.modules.keys())
44
>>> print sys.modules.keys()
['copy_reg', 'sre_compile', '_sre', 'encodings', 'site', '__builtin__', 'sysconfig', '__main__', 'encodings.encodings', 'abc', 'posixpath', '_weakrefset', 'errno', 'encodings.codecs', 'sre_constants', 're', '_abcoll', 'types', '_codecs', 'encodings.__builtin__', '_warnings', 'genericpath', 'stat', 'zipimport', '_sysconfigdata', 'warnings', 'UserDict', 'encodings.utf_8', 'sys', 'virtualenvwrapper', '_osx_support', 'codecs', 'readline', 'os.path', 'sitecustomize', 'signal', 'traceback', 'linecache', 'posix', 'encodings.aliases', 'exceptions', 'sre_parse', 'os', '_weakref']
>>> import urllib
>>> print len(sys.modules.keys())
70
>>> print sys.modules.keys()
['cStringIO', 'heapq', 'base64', 'copy_reg', 'sre_compile', '_collections', '_sre', 'functools', 'encodings', 'site', '__builtin__', 'sysconfig', 'thread', '_ssl', '__main__', 'operator', 'encodings.encodings', '_heapq', 'abc', 'posixpath', '_weakrefset', 'errno', '_socket', 'binascii', 'encodings.codecs', 'urllib', 'sre_constants', 're', '_abcoll', 'collections', 'types', '_codecs', 'encodings.__builtin__', '_struct', '_warnings', '_scproxy', 'genericpath', 'stat', 'zipimport', '_sysconfigdata', 'string', 'warnings', 'UserDict', 'struct', 'encodings.utf_8', 'textwrap', 'sys', 'ssl', 'virtualenvwrapper', '_osx_support', 'codecs', 'readline', 'os.path', 'strop', '_functools', 'sitecustomize', 'socket', 'keyword', 'signal', 'traceback', 'urlparse', 'linecache', 'itertools', 'posix', 'encodings.aliases', 'time', 'exceptions', 'sre_parse', 'os', '_weakref']
>>> import urllib #again!
>>> print len(sys.modules.keys()) #has not loaded any additional modules
70
让我们试一试:
import sys
>>> sys.modules["foo"] = "bar" # Let's pretend we imported a module named "foo", which is a string.
>>> print __import__("foo")
bar # Not a module, that's my string!
如您所见,如果在sys.modules
上找到了一个模块,您将获得对它的新引用。就是这样。
请注意,这意味着模块应设计为在导入时不会产生副作用(例如打印内容)。
在交互式会话之外重新加载模块通常也不是一个很好的做法(尽管它有其用例) - 其他答案将详细说明您将如何做到这一点。
【讨论】:
"什么都没有,如果一个模块已经被导入,它不会再次加载。" Python(至少 2.7)绝对不能保证这一点。特别是如果,例如,多个线程最终导入同一个模块。【参考方案2】:Python 脚本只会加载一个模块一次。要重新加载它,请使用:
reload() # Python 2
和
imp.reload() # Python 3
【讨论】:
【参考方案3】:仅在第一次执行 import
语句时加载模块。另见reload()
和this question。您可以检查 sys.modules
以了解哪些模块已被加载。
【讨论】:
以上是关于当一个模块被导入两次时会发生啥?的主要内容,如果未能解决你的问题,请参考以下文章