The Python __init__.py file serves two main functions:
- 
It is used to label a directory as a python package to make it visible so other python files can re-use the nested resources (e.g. the incrmethod defined insidehelpers/file1.py):from helpers.file1 import incr result = incr(42) assert result == 43A side effect is that – with some not-recommended workarounds – developers do not have to care about the method’s location in your package hierarchy: helpers/ ├── __init__.py ├── file1.py ├── file2.py ├── ... └── fileN.pyFor that, simply fill the __init__.pyfile with the following content:from file1 import * from file2 import * ... from fileN import *Therefore, even though it is always a good practice to explicitely mention the source, they can simply use: from helpers import incr result = incr(42) assert result == 43
- 
It is used to define variables or to initialise objects like loggingat the package level and import time (to make them accesible at a global package level):from helpers.file3 import MY_VAR print(MY_VAR)
Still blur? Thereafter an easy example to understand:
First, let’s plot some context
You have the following project structure:
playground_packages
├── helpers/
    └── utils.py
└── main.py
The utils.py file contains:
def incr(n:list[float]) -> list[float]:
    return [x+1 for x in n]
if __name__ == "__main__":
    pass
Note: you could have also used the map and lambda methods instead. However, here is a nice example to show about list comprehension.  The alternave version would have looked like:
list(map(lambda x: x+1, n))
The main.py file is looking like the following:
from helpers.utils import incr
def main() -> None:
    result = incr([1,2,3,4,5])
    print(result)
if __name__ == "__main__":
    main()
Notes:
- Why we haven’t used import helpers.utilsorimport *is explained here (to do).
- The if __name__ == "__main__"conditional statement is explained here (to do).
__init__.py to label a folder as Python package
Jumping back to our example, if you try to run the code with the current configuration, you will get the following error:
> python main.py
Traceback (most recent call last):
File "path/to/playground_package/main.py", line 1, in <module>
    from helpers.utils import incr
ModuleNotFoundError: No module named 'helpers'
This is because the helpers directory is not yet visible for Python. Python is actively looking for Python packages but cannot find any. A package is a folder that contains a __init__.py file.
Simply edit our current structure for the following:
playground_packages
├── helpers/
    ├── __init__.py
    └── utils.py
└── main.py
Now, it you try again, it will succeed:
> python main.py
[2, 3, 4, 5, 6]
The main take-away is:
If you want to split-up your code in different folders and files (to make your code more readable and debuggable), you must create a __init__.py file under each folder so they become visible for Python and can therefore be used and refered to in your code using import.
__init__.py to define global variables
In our previous example, the __init__.py file is empty. We can edit it, adding the following line:
MY_LIST = [2,4,6,8,10]
This variable is accessible even by the main function:
from helpers import MY_LIST
from helpers.utils import incr
def main() -> None:
    result = incr(MY_LIST)
    print(result)
if __name__ == "__main__":
    main()
> python main.py
[3, 5, 7, 9, 11]
Note: it is better to define variables in a config.py or constants.py file rather than in a __init__.py file. However, __init__.py becomes handy when it comes to instanciate objects such as logging or dynaconf. More on that will follow in another article. 
You are now ready to fit your code together like Russian dolls 🪆
