This is my project structure (Python 3.5.1.):
a
├── b.py
└── __init__.py
Case 1
File
b.pyis empty.File
__init__.pyis:print(b)
If we run import a, the output is:
NameError: name 'b' is not defined
Case 2
File
b.pyis empty.File
__init__.pyis:import a.b print(b)
If we run import a, the output is:
<module 'a.b' from '/tmp/a/b.py'>
Question
Why doesn't the program fail in Case 2?
Usually if we run import a.b then we can only reference it by a.b, not b. Hopefully somebody can help explain what's happening to the namespace in Case 2.
2 Answers 2
Python adds modules as globals to the parent package after import.
So when you imported a.b, the name b was added as a global to the a module, created by a/__init__.py.
From the Python 3 import system documentation:
When a submodule is loaded using any mechanism (e.g. importlib APIs, the import or import-from statements, 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.
Bold emphasis mine. Note that the same applies to Python 2, but Python 3 made the process more explicit.
Comments
An import statement brings a module into scope. You imported b, so there it is, a module object.
Read the documentation for import:
The basic import statement (no from clause) is executed in two steps:
- find a module, loading and initializing it if necessary
- define a name or names in the local namespace for the scope where the import statement occurs.
You didn't import b in the first case.
3 Comments
import a.b; print(b) in a __main__ script then it will fail. But it doesn't fail in Case 2 here.import a.b binds the name a in a namespace. What is special here is that b is a submodule of a and thus the import internals set the name b in the namespace of a. That results in a global b in that the namespace of a, i.e. __init__.py. If this was any other module the name b would not have appeared like this.b in the second case either, but it was added anyway.
bis introduced to the namespace ofaby theimport a.bstatement. But I'm not sure about the details. Nor do I know whether it's an explicitly supported feature.aandb.ashould be there. But why isbalso there? The most logical thing I can guess is:ais introduced into the current scope, thenbis introduced into the scope ofa. But the current scope is the same as the scope ofawhen executinga/__init__.py. Need confirmation.bthere too? It was never explicitly imported.import a.bonly addsa, normally.