I've noticed that asyncio/init.py
from python 3.6 uses the following construct:
from .base_events import *
...
__all__ = (base_events.__all__ + ...)
The base_events
symbol is not imported anywhere in the source code, yet the module still contains a local variable for it.
I've checked this behavior with the following code, put into an __init__.py
with a dummy test.py
next to it:
test = "not a module"
print(test)
from .test import *
print(test)
not a module
<module 'testpy.test' from 'C:\Users\MrM\Desktop\testpy\test.py'>
Which means that the test
variable got shadowed after using a star import.
I fiddled with it a bit, and it turns out that it doesn't have to be a star import, but it has to be inside an __init__.py
, and it has to be relative. Otherwise the module object is not being assigned anywhere.
Without the assignment, running the above example from a file that isn't an __init__.py
will raise a NameError
.
Where is this behavior coming from? Has this been outlined in the spec for import system somewhere? What's the reason behind __init__.py
having to be special in this way? It's not in the reference, or at least I couldn't find it.
With your new skills, you can confidently import packages and modules from the Python standard library, third party packages, and your own local packages. Remember that you should generally opt for absolute imports over relative ones, unless the path is complex and would make the statement too long.
Relative import specifies object or module imported from its current location, that is the location where import statement resides. There two types of relative imports : Implicit relative imports : Implicit relative import have been disapproved in Python(3.
The __init__.py file can contain the same Python code that any other module can contain, and Python will add some additional attributes to the module when it is imported.
Python is a regular language, which means that function definitions, class definitions, import statements etc. mostly work at any scope. But there's an exception for “ from ... import * “, which can't be used inside a function.
This behavior is defined in The import system documentation section 5.4.2 Submodules
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 package spam has a submodule foo, after importing spam.foo, spam will have an attribute foo which is bound to the submodule.
A package namespace includes the namespace created in __init__.py
plus extras added by the import system. The why is for namespace consistency.
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'] and sys.modules['spam.foo'] (as you would after the above import), the latter must appear as the foo attribute of the former.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With