I have a Python project with the following structure:
testapp/
├── __init__.py
├── api
│ ├── __init__.py
│ └── utils.py
└── utils.py
Al
From the import system documentation:
When a submodule is loaded using any mechanism (e.g.
importlibAPIs, theimportorimport-fromstatements, or built-in__import__()) a binding is placed in the parent module’s namespace to the submodule object. For example, if packagespamhas a submodulefoo, after importingspam.foo,spamwill have an attributefoowhich is bound to the submodule. Let’s say you have the following directory structure:spam/ __init__.py foo.py bar.pyand
spam/__init__.pyhas the following lines in it:from .foo import Foo from .bar import Barthen executing the following puts a name binding to
fooandbarin thespammodule:>>> import spam >>> spam.foo>>> spam.bar 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 thefooattribute of the former.
If you do from testapp.api.utils import x, the import statement will not load utils into the local namespace. However, the import machinery will load utils into the testapp.api namespace, to make further imports work right. It just happens that in your case, testapp.api is also the local namespace, so you're getting a surprise.