Lesson 9
No Object is an Island
Chapter 8: Python packages
The __init__.py file
So why do you still need __init__.py
then?
Turning a directory into a module
__init__.py
can actually turn a directory name into a module. So, you can now import sound
as if there were a sound.py
file. The file __init__.py
is basically a replacement for sound.py
.
sound/
__init__.py
formats/
__init__.py
wavread.py
wavwrite.py
...
effects/
__init__.py
echo.py
surround.py
...
filters/
__init__.py
equalizer.py
vocoder.py
...
What this means is that you can put anything inside __init__.py
, and it will run when you import sound
. Similarly, if you write some code in sound/__init__.py
and sound/format/__init__.py
that prints out something, then both files will be executed when you import sound.formats
. Try this!
Including metadata
You can also include a docstring in the first line of sound/__init__.py
, and this will print out when you type sound.__doc__
after you import sound
.
It’s also quite common to include dunder variables like the following at the beginning of an __init__.py
file (and even at the beginning of a normal module file).
__version__ = "0.8"
__author__ = "Josiah Wang"
The __all__
magic variable
The biggest use for __init__.py
is to set the __all__
magic variable. This will allow you to use the wildcard from sound.formats import *
.
You can try this. First try the following without adding anything to sound/formats/__init__.py
. Neither wavread
nor wavwrite
will be imported.
>>> from sound.formats import *
>>> wavread
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'wavread' is not defined
>>> dir() # this shows what variables are currently available in the namespace
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__']
Then add the following line to sound/format/__init__.py
.
__all__ = ["wavread", "wavwrite"]
If you run the following again, it should now successfully import both wavread
and wavwrite
(you may need to restart the interpreter to recompile the package).
>>> from sound.formats import *
>>> wavread
<module 'sound.formats.wavread' from '/xxx/xxx/xxx/sound/formats/wavread.py'>
>>> wavwrite
<module 'sound.formats.wavwrite' from '/xxx/xxx/xxx/sound/formats/wavwrite.py'>
>>> dir()
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'wavread', 'wavwrite']
That’s as far as we will cover for packages! You can reorganise your robot project files into packages once it has grown larger, but this is just a bonus task for you to explore on your own.