问题
Imports in an __init__.py
seem to behave differently when the file is run, to when it is imported.
If we have the following files:
run.py
:
import test
test/b.py
:
class B(object):
pass
test/__init__.py
:
from b import B
print B
print b
If we run __init__.py
we get an error as I expect:
% python test/__init__.py
<class 'b.B'>
Traceback (most recent call last):
File "test/__init__.py", line 6, in <module>
print b
NameError: name 'b' is not defined
But if we run.py
then we don't:
% python run.py
<class 'test.b.B'>
<module 'test.b' from '~/temp/test/b.py'>
I would expect the behaviour to be the same. Why does this work?
This only works if we do it in an __init__.py
. If we:
mv __init__.py a.py
touch __init__.py
and make run.py
:
import test.a
Then we do get the error.
回答1:
The situation is the following: you have a script (run.py
), a package test
and its submodule test.b
.
Whenever you import a submodule in Python, the name of that submodule is automatically stored into the parent package. So that when you do import collections.abc
(or from collections.abc import Iterable
, or similar), the package collections
automatically gets the attribute abc
.
This is what's happening here. When you do:
from b import B
the name b
is automatically loaded into test
, because b
is a submodule of the test
package.
Even if you don't do import b
explicitly, whenever you import that module, the name is placed into test
. Because b
is a submodule of test
, and it belongs to test
.
Side node: your code won't work with Python 3, because relative imports have been removed. To make your code work with Python 3, you would have to write:
from test.b import B
This syntax is perfectly identical to from b import B
, but is much more explicit, and should help you understand what's going on.
Reference: the Python reference documentation also explains this behavior, and includes a helpful example, very similar to this situation (the difference is just that an absolute import is used, instead of a relative import).
When a submodule is loaded using any mechanism (e.g.
importlib
APIs, theimport
orimport-from
statements, or built-in__import__()
) a binding is placed in the parent module's namespace to the submodule object. For example, if packagespam
has a submodulefoo
, after importingspam.foo
,spam
will have an attributefoo
which is bound to the submodule.Let's say you have the following directory structure:
spam/ __init__.py foo.py bar.py
and
spam/__init__.py
has the following lines in it:from .foo import Foo from .bar import Bar
then executing the following puts a name binding to
foo
andbar
in thespam
module:>>> import spam >>> spam.foo <module 'spam.foo' from '/tmp/imports/spam/foo.py'> >>> spam.bar <module 'spam.bar' from '/tmp/imports/spam/bar.py'>
Given Python's familiar name binding rules this might seem surprising, but it's actually a fundamental feature of the import system. The invariant holding is that if you have
sys.modules['spam']
andsys.modules['spam.foo']
(as you would after the above import), the latter must appear as thefoo
attribute of the former.
来源:https://stackoverflow.com/questions/34434749/imports-behave-differently-when-in-init-py-that-is-imported