Wamaitha N.
—
The ProblemJump To Solution
What is __init__.py
used for in Python?
The Solution
In Python projects, if you create a file called __init__.py
in a directory then Python will treat that directory as a package. A package in Python is a collection of modules (individual .py files) that can be imported into other Python files.
In older versions of Python (before 3.3), it was necessary to create an __init__.py
file in a package before you could use import statements in the form from mypackage import mymodule
. Since version 3.3 and the implementation of PEP 420, Python will automatically create “Namespace Packages” implicitly in many cases. This means that __init__.py
is now often optional, but it’s still useful to structure your initialization code and define how statements like from mypackage import *
should work.
Let’s take a look at what the __init__.py
file does with an example Python package. Imagine we have a calculator
script that imports a divider
and multiplier
module from an operations
package.
Our directory structure looks like this:
Click to Copy
├── calculator.py└── operations ├── divider.py └── multiplier.py
And our three files look like this:
Click to Copy
# calculator.pyfrom operations import multiplier, dividermymultiplier = multiplier.Multiplier()result = mymultiplier.multiply(2, 5)print(f"2 x 5 is {result}")mydivider = divider.Divider()result = mydivider.divide(10, 2)print(f"10 / 2 is {result}")
Click to Copy
# operations/divider.pyclass Divider: def divide(self, a, b): return a / b
Click to Copy
# operations/multiplier.pyclass Multiplier: def multiply(self, a, b): return a * b
In Python 3.3 and above, this works fine. When we run from operations import multiplier
, Python treats the operations
subdirectory as a Namespace Package and imports the multiplier
module from that package. In previous versions of Python, this would have raised an error:
Click to Copy
File "calculator.py", line 1, in <module> from operations import multiplierImportError: No module named operations
And simply adding a blank file called __init__.py
in the operations
directory would fix the issue.
Click to Copy
touch operations/__init__.py
Now running the calculator.py
script would work as expected:
Click to Copy
2 x 5 is 1010 / 2 is 5.0
What does __init__.py
do?
Even in Python 3.3 and above, creating an __init__.py
file will change the behavior of your scripts, though these changes are more subtle than in older versions of Python. It can automatically define the __file__
metadata of your package, which is useful.
If you import a package and inspect it with Python’s built-in dir
function, you’ll see a difference with and without having an __init__.py
file.
Add the following to the top of calculator.py
:
Click to Copy
# calculator.pyimport operationsprint(dir(operations))print(operations.__file__)
This shows us all the variables available in the operations package and prints out its path on the system. Without an __init__.py
file in your operations
subdirectory, you’ll see the following:
Click to Copy
['__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__']None
You can see that Python has automatically added some metadata in the variables starting and ending with two underscores, like __file__
.
However, the None
on the next line shows that the __file__
variable is blank.
If you create an __init__.py
file in the operations
subdirectory, it is now an explicit package. If you run the calculator.py
file again, you’ll now see some differences in the output:
Click to Copy
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__']/Users/g/python_init_example/operations/__init__.py
Now the full path to the __init__.py
file has been used as the __file__
variable for the operations
package. Python has also added the __builtins__
and __cached__
metadata variables for us.
Using __init__.py
to run code and control *
imports
Larger and more complicated packages often use __init__.py
to better organize code and to run any initialization that should be run automatically when the package is imported.
For example, you could add the line print("Hi from __init__.py")
to your operations/__init__.py
file. Now if you import the operations package, it will run the print
statement immediately:
Click to Copy
python_init_example$ python3Python 3.11.5 (main, Aug 24 2023, 15:09:45) [Clang 14.0.3 (clang-1403.0.22.14.1)] on darwinType "help", "copyright", "credits" or "license" for more information.>>> import operationsHi from init
A common thing to define in the __init__.py
is the __all__
variable. This overwrites what modules and functions should be imported when a user runs an import statement in the form from mypackage import *
.
By default, Python does not import modules from a package. So if we changed the first line in our calculator.py
file to import everything from operations
, it would not work.
Click to Copy
# calculator.py# broken import unless we explicitly define `__all__` in `__init__.py`from operations import *mymultiplier = multiplier.Multiplier()result = mymultiplier.multiply(2, 5)print(f"2 x 5 is {result}")mydivider = divider.Divider()result = mydivider.divide(10, 2)print(f"10 / 2 is {result}")
If we run calculator.py
now, we’ll get an error:
Click to Copy
Traceback (most recent call last): File "/Users/g/python_init_example/calculator.py", line 3, in <module> mymultiplier = multiplier.Multiplier() ^^^^^^^^^^NameError: name 'multiplier' is not defined
But if we add the following line to operations/__init__.py
:
Click to Copy
__all__ = ['divider', 'multiplier']
the calculator.py
script will run as expected:
Click to Copy
2 x 5 is 1010 / 2 is 5.0