__init__.py is a special file in Python packages.
It serves multiple purposes:
✔ Marks a directory as a Python package
✔ Controls package initialization
✔ Defines package-level behavior
✔ Simplifies imports
✔ Organizes project structure
__init__.py is a special Python file placed inside a directory.
Example structure:
my_project/
│
├── main.py
└── my_package/
├── __init__.py
├── module1.py
└── module2.py
👉 The presence of __init__.py tells Python:
"This directory is a package"
Think of:
👉 Folder = Package Container
👉 init.py = Package Entry Point
Similar to:
- main.py → program entry
- init.py → package entry
Historically:
Without __init__.py, Python did not treat folders as packages.
Modern Python (3.3+) supports namespace packages, but:
__init__.py is still best practice.
Without __init__.py → Just a folder
With __init__.py → Python package
Code inside __init__.py runs when the package is imported.
# my_package/__init__.py
print("Package initialized!")import my_packageOutput:
Package initialized!
Runs automatically.
One of the most powerful uses.
from my_package.module1 import func1
from my_package.module2 import func2# my_package/__init__.py
from .module1 import func1
from .module2 import func2Now:
from my_package import func1, func2Cleaner API design.
__init__.py = Public Interface of Package
# __init__.py
version = "1.0"
author = "Himanshu"import my_package
print(my_package.version)Useful for:
✔ Constants
✔ Setup logic
✔ Shared objects
Example:
# __init__.py
DEFAULT_TIMEOUT = 30# __init__.py
__all__ = ["module1"]Controls:
from my_package import *Prevents accidental exposure of internals.
app/
│
├── main.py
└── utils/
├── __init__.py
├── math_utils.py
└── string_utils.py
from .math_utils import add
from .string_utils import capitalizefrom utils import add, capitalizeBeautiful, clean imports.
| Confusion | Reality |
|---|---|
| init.py required? | Best practice ✅ |
| Must contain code? | ❌ Can be empty |
| Same as constructor? | ❌ Completely different |
| Runs automatically? | ✅ Yes |
| Only for imports? | ❌ Many uses |
| Feature | init.py | init() |
|---|---|---|
| Type | File | Method |
| Purpose | Package behavior | Object initialization |
| Runs When | Package import | Object creation |
| Scope | Package level | Object level |
✔ Heavy logic inside init.py
✔ Complex side effects
✔ Circular imports
✔ Hidden mutations
✔ Keep lightweight
✔ Use for imports & constants
✔ Avoid heavy computation
✔ Design clean public API
✔ Use explicit exports
✔ Organize package structure
| Advantage | Benefit |
|---|---|
| Clean imports | Better developer experience |
| Package control | Hide internals |
| Initialization logic | Setup behavior |
| Centralized API | Professional design |
| Structure clarity | Scalable projects |
| Concept | Truth |
|---|---|
| init.py | Package initializer file |
| Purpose | Define package behavior |
| Runs automatically | ✅ Yes |
| Required? | Best practice ✅ |
| Can be empty? | ✅ Yes |
| Enables | Clean imports & API design |
- Create your own package with init.py
- Add initialization print statement
- Simplify imports using init.py
- Add package-level constants
- Experiment with all
- Create multi-module package
- Trigger circular import mistake (for learning)