I was just wondering why __import__()
calls a __init__
module twice when loading a package.
test.py
testpkg/
__init__.py
test.py
:
pkg = __import__("testpkg", fromlist=[''])
__init__.py
:
print "Called."
After calling py开发者_JAVA百科thon test.py
, Called. will be printed out twice. Why does python execute the __init__
"module" twice?
This is a Python bug. Passing the null string as an element of fromlist
is illegal, and should raise an exception.
There's no need to include ""
in fromlist
; that's implicit--the module itself is always loaded. What's actually happening is the module.submodule
string is using the null string, resulting in the module name testpkg.
, with a trailing period. That gets imported literally, and since it has a different name than testpkg
, it's imported as a separate module.
Try this:
pkg = __import__("testpkg", fromlist=[''])
import sys
print sys["testpkg"]
print sys["testpkg."]
... and you'll see the duplicate module.
Someone should probably file a ticket on this if there isn't already one; too tired to do it myself right now.
Using the fromlist=['']
hack to import a specific module is explicitly frowned upon by python-dev. While it has been filed as an issue, the chances of it being fixed are low specifically because this is viewed as a mis-use of fromlist
to begin with instead of necessarily a bug and a better solution is available.
What you should be doing is using importlib.import_module
(available in the standard library for Python 2.7 and Python 3.1, or from PyPI with compatibility back to Python 2.3 along with being included in Django since 1.1 as django.utils.importlib
). It will prevent this problem from happening, provides a better programmatic interface for importing modules, and even lets you use relative imports when you specify the package you are importing from.
If you really cannot use importlib (e.g., PyPI dependencies are not allowed even though the code you can freely copy thanks to the PSF license and it being rather short), then you should be doing __import__("some.module"); mod = sys.modules["some.module"]
. That is the official, python-dev sanctioned solution to the problem (but only after you cannot use importlib
).
精彩评论