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.pyYou could import module1 and module2 in the main.py file like this:
from myproject import module1, module2Or like this:
import myproject.module1You could also import submodule1 and submodule2 from the subpackage like this:
import myproject.subpackage.submodule1
import myproject.subpackage.submodule2Defining 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.pyThe __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 + bThe 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 / 9The 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.
