As far as I understand from the python docs , from package import x
statement should bind only x
, but not package
, into the current namespace. But in practice, if package
is a relative name, it is also bound sometimes!
Let me provide an example. Consider the following file hierarchy:
root/
package/
__init__.py
subpackage/
__init__.py
subpackage/__init__.py:
foo = 42
package/__init__.py:
from os import name
from .subpackage import foo
print(globals().get('name'))
print(globals().get('os'))
print(globals().get('foo'))
print(globals().get('subpackage'))
Now let's run python (either v2 or v3) interpreter from the root
directory and execute
>>> import package
The first three output lines are predictable:
posix
None
42
But the last one is <module 'package.subpackage' ...>
rather than None
, and this confuses me somewhat.
Have I missed something? Is it expected behavior? What is the reason?
The situation seems even more weird to me in this case:
root/
__init__.py # Empty.
package/
__init__.py
another_package/
__init__.py
another_package/__init__.py:
bar = 33
package/__init__.py:
from ..another_package import bar
print(globals().get('another_package'))
Now I run this outside the root:
>>> import root.package
None # OK.
>>> dir(root.package)
['__builtins__', ..., '__path__', 'bar'] # OK.
>>> dir(root)
['__builtins__', ..., '__path__', 'another_package', 'package'] # What?!
Why did another_package
appear in dir(root)
?
It's important to realize modules are loaded once at most (unless they are explicitly reloaded ). If a module is imported in multiple modules, the same module object is referenced by them all. Eg:
Module M.py
bar = 10
Module A.py
import M
M.bar = 4
Module B.py
import M
M.bar = 6
So:
>>> import M
>>> M.bar
10
>>> import A
>>> M.bar # A is referencing the same M module object!!
4
>>> import B
>>> M.bar # B is referencing the same M module object!!
6
Now, when the statement from ..another_package import bar
is executed it is basically equivalent to executing from root.another_package import bar
. Since another_package
is indeed a module inside the root
package, the statement succeeds which results with the following effects (there may be more, but for this purposes let's focus on these 3):
root
is loaded if not previously loaded (its' __init__.py
is run) bar
is imported into the current namespace another_package
is added as an attribute to root
module object Some developers are not completely aware of items 1 and 3.
Back to your question: Let's see what happens when import root.package
is executed, in this order:
root
's __init__.py
is run (because root
wasn't loaded yet) package
's __init__.py
is run (because package
wasn't loaded yet) from ..another_package import bar
is executed which has the side effects mentioned above, most notably, the (Yes. THE object. There is only one per each module, remember?) module object of root
has the attribute another_package
added to it. This explains why another_package
appears in root
's dir
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.