If you are a Python developer, chances are high that you may have come across the __init__.py
file. It has several roles in a Python project.
- To show that a directory is a Python package. This allows importing modules contained in that directory as top-level modules.
- To define variables and functions that should be available when the package is imported.
- To specify any initialization code that should be run when the package is imported.
- Organize code and make it easier to import modules
Let’s see all these use cases in detail now.
Showing a directory as a Python package
The presence of the __init__.py
file in a directory tells Python that the directory is a Python package. This allows you to import modules contained in that directory as top-level modules (like a module in the current directory).
For example, if you have a directory structure like this:
main.py
myproject/
|-- __init__.py
|-- module1.py
|-- module2.py
|-- subpackage/
|-- __init__.py
|-- submodule1.py
|-- submodule2.py
You could import module1
and module2
in the main.py
file like this:
from myproject import module1, module2
Or like this:
import myproject.module1
You could also import submodule1 and submodule2 from the subpackage like this:
import myproject.subpackage.submodule1
import myproject.subpackage.submodule2
Defining variables and functions
Variables and functions defined in __init__.py
file are available in the package when it is imported. For example, you could define a list in __init__.py
like this:
names = ['John', 'Paul', 'George', 'Ringo']
Then, you could access the names list from any module in the myproject package like this:
from myproject import names
print(names)
Specifying initialization code
You can also use the __init__.py
file to specify any initialization code that should be run when the package is imported. For example, you could load data from a file when the package is imported. This would allow you to access the data from any module in the package without having to read the data from the file each time it is needed.
Consider the following example.
# myproject/
# |-- __init__.py
# |-- data.py
# |-- main.py
# myproject/__init__.py
import data
import json
def load_data_from_file(info.json):
print("Loading data into memory...")
with open(filename) as f:
return json.load(f)
data.items = load_data_from_file("items.json")
# myproject/data.py
items = []
def get_item(id):
for item in items:
if item["id"] == id:
return item
return None
# myproject/main.py
import myproject
item = myproject.data.get_item(123)
if item:
print(f"Found item: {item['name']}")
else:
print("Item not found.")
In this example, the __init__.py
file reads the data from info.json
and stores it in the items variable. This can then be accessed from the data module.
This allows you to load the data into memory only once, when the package is imported, rather than reading the data from the file each time it is needed.
This can be useful if the data is large and takes a long time to read from the file. In this way, initialization can be used to improve performance.
Organizing code
Here is an example of how you could use modules and packages to organize a simple calculator application in Python.
calculator/
__init__.py
operations/
__init__.py
addition.py
subtraction.py
multiplication.py
division.py
conversions/
__init__.py
temperature.py
distance.py
weight.py
main.py
The __init__.py
file in the calculator directory is used to show that the calculator directory is a Python package. The __init__.py
file in the operations and conversions directories is used to show these directories as Python packages.
The calculator package contains the operations and conversions packages, each containing multiple modules.
Here is what the code for the addition module in the operations package could look like this:
# calculator/operations/addition.py
def add(a, b):
return a + b
The other operation modules (subtraction, multiplication, division) would be similar with the appropriate operation.
Here is what the code for the temperature module in the conversions package could look like:
# calculator/conversions/temperature.py
def celsius_to_fahrenheit(c):
return c * 9 / 5 + 32
def fahrenheit_to_celsius(f):
return (f - 32) * 5 / 9
The other conversion modules (distance, weight) would be similar with the appropriate conversion.
Finally, the code for the main module in the calculator package could look like:
# calculator/main.py
from operations import addition, subtraction, multiplication, division
from conversions import temperature, distance, weight
print(addition.add(1, 2))
print(subtraction.subtract(5, 3))
print(temperature.celsius_to_fahrenheit(0))
print(distance.miles_to_kilometers(1))
It is easier to reuse functions in other portions of the application by organizing the code into modules and packages. It is also easier to understand and maintain the code.