# Python __init__.py File: Purpose and Usage Guide

> Use __init__.py to mark directories as Python packages, control wildcard imports with __all__, and run initialization code when a package is imported

**URL:** https://sentry.io/answers/what-is-init-py-for-in-python/

---

## The Problem

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](https://peps.python.org/pep-0420/), 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:

```
├── calculator.py
└── operations
    ├── divider.py
    └── multiplier.py
```

And our three files look like this:

```python
# calculator.py

from operations import multiplier, divider

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}")
```

```python
# operations/divider.py

class Divider:

    def divide(self, a, b):
        return a / b
```

```python
# operations/multiplier.py

class 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:

```
File "calculator.py", line 1, in <module>
  from operations import multiplier
ImportError: No module named operations
```

And simply adding a blank file called `__init__.py` in the `operations` directory would fix the issue.

```bash
touch operations/__init__.py
```

Now running the `calculator.py` script would work as expected:

```
2 x 5 is 10
10 / 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`:

```python
# calculator.py

import operations
print(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:

```
['__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:

```
['__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:

```bash
python_init_example$ python3
Python 3.11.5 (main, Aug 24 2023, 15:09:45) [Clang 14.0.3 (clang-1403.0.22.14.1)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import operations
Hi 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.

```python
# 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:

```
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`:

```python
__all__ = ['divider', 'multiplier']
```

the `calculator.py` script will run as expected:

```
2 x 5 is 10
10 / 2 is 5.0
```

---

*Source: [sentry.io/answers/what-is-init-py-for-in-python/](https://sentry.io/answers/what-is-init-py-for-in-python/)*
