__import__()为何调用__init__.py两次?
我在想,为什么在加载一个包的时候,__import__()
会调用 __init__
模块两次。
test.py
testpkg/
__init__.py
test.py
:
pkg = __import__("testpkg", fromlist=[''])
__init__.py
:
print "Called."
当我运行 python test.py
时,Called. 会被打印两次。为什么 Python 会执行 __init__
这个“模块”两次呢?
2 个回答
使用 fromlist=['']
这种方法来导入特定模块是被 Python 开发者明确反对的。虽然这个问题已经被提出来了,但解决的可能性不大,因为大家认为这其实是对 fromlist
的误用,而不是一个真正的bug,而且有更好的解决办法。
你应该使用 importlib.import_module
来导入模块(这个在 Python 2.7 和 Python 3.1 的标准库中都有,或者你可以从 PyPI 下载,支持到 Python 2.3,并且在 Django 1.1 之后也包含了这个功能,叫做 django.utils.importlib
)。这样可以避免这个问题的发生,提供了更好的模块导入接口,甚至在指定导入的包时,还能使用相对导入。
如果你真的不能使用 importlib(比如说不允许使用 PyPI 的依赖,尽管你可以自由复制代码,因为有 PSF 许可证,而且代码也很短),那么你应该使用 __import__("some.module"); mod = sys.modules["some.module"]
。这是官方认可的解决方案(但只有在无法使用 importlib
的情况下才用)。
这是一个Python的bug。把空字符串作为fromlist
的元素是不合法的,应该会引发一个错误。
其实在fromlist
里不需要包含""
;因为模块本身总是会被加载,这个是默认的。真正发生的事情是module.submodule
这个字符串用了空字符串,导致模块名变成了testpkg.
,后面多了一个点。这样的话,它会被直接导入,而因为它的名字和testpkg
不一样,所以它被当作一个独立的模块导入了。
试试这个:
pkg = __import__("testpkg", fromlist=[''])
import sys
print sys["testpkg"]
print sys["testpkg."]
...你会看到重复的模块。
如果还没有人提这个问题,可能应该有人去反馈一下;我现在太累了,没力气去做。