Reputation: 3968
As the Python documentation states, a module import (as well as imports from a module) is always executing possible parent modules. For example with these files that constitute a regular package:
a_package/
__init__.py
a_submodule.py
An import from a_submodule
in a completely different package, e.g.
from a_package.a_submodule import an_object
would first execute a_package/__init__.py
before executing a_package/a_submodule.py
and eventually binding an_object
into the namespace where the import is stated.
I'm wondering what the design rationale or technical necessity behind this is. In particular because it seems counter-intuitive to me as the usual package regime is an ordered graph where the parent modules are depending on contents from their subpackages, not vice versa. And as a matter of fact, if that import statement example was evaluated in a_package/__init__.py
, it wouldn't trigger an execution of itself. Of course, because that'd be a cyclic dependency, yet it shows that submodules are not depending on their parent modules.
Upvotes: 1
Views: 324
Reputation: 39838
There are several reasons. The most important from a capability perspective is that a package can use mechanisms like __path__
to help find its submodules, and that obviously won’t work if it weren’t configured before proceeding with the submodule import. Another is a convenience: if a package needs initialization before its modules can be used, it can be put into __init__.py
rather than having every module need from . import startup
.
Moreover, at what other time should the package be initialized? It doesn’t make sense to wait until all submodules are imported, since that might never happen; while it could be “after the first import of a submodule finishes”, that would still be before the import of other submodules and would be inconsistent and arbitrary. In particular, no module could use the contents of its parent __init__.py
in case it was the first among its siblings to be imported.
As for the cyclic dependency, Python has always supported those (at least for absolute imports): importing a module already being imported simply produces a reference to the module object (in its partially formed state). The behavior of from . import foo
(which is, as an aside, usually a bad idea as part of executing __init__.py
) is no exception; as the “extra import” is just into sys.modules
anyway, it has no effect at all.
Upvotes: 1