What __init__.py does in a Python package
Use __init__.py to define a regular package and a small public interface, while understanding import caching, namespace packages, and initialization side effects.
__init__.py marks a directory as a regular Python package and supplies the code executed when that package is initialized. It can be empty. The exact name includes two underscores on each side of init; a file named init.py has no equivalent special role.
Define a regular package
mypackage/
├── __init__.py
├── module1.py
└── module2.py
When the package's parent is on the import path, these imports are available:
import mypackage.module1
from mypackage import module2
On the first normal import, Python initializes the parent package before loading the requested child module. For a chain of regular packages such as a.b.c, the relevant parents are initialized in order. Cached packages are normally reused on later imports.
The file alone does not make an arbitrary directory importable from every working directory. Install the package or provide an intentional import path.
Keep initialization small
A library can define package-level defaults and avoid configuring the application's global logging:
# mypackage/__init__.py
import logging
logging.getLogger(__name__).addHandler(logging.NullHandler())
DEFAULT_TIMEOUT = 30
Avoid printing, opening network connections, or doing expensive work merely because someone imports a child module. An initializer can execute arbitrary code, so import time and side effects affect every user of that package.
Expose a focused public interface
If module1.py defines Client and module2.py defines helper, the initializer can re-export them:
# mypackage/__init__.py
from .module1 import Client
from .module2 import helper
__all__ = ["Client", "helper"]
Callers can then write from mypackage import Client. __all__ controls what a star import exports; it does not make other attributes private or prevent an explicit import. Re-export only what belongs in the supported interface.
Keep dependencies directional. Importing children from the initializer while those children immediately access names from the partly initialized parent can produce circular-import failures.
When can the file be omitted?
Python 3.3+ supports implicit namespace packages without __init__.py. Their portions can be spread across multiple import-path locations. This is useful when separate distributions deliberately contribute to one namespace.
Use a regular package when it matches the project, especially when package initialization is needed. Do not add or remove __init__.py casually in a namespace design: it changes discovery behavior, and the build tool must package the intended files correctly.
FAQ
Does the initializer run exactly once?
A successful ordinary import is cached in sys.modules, so later imports normally reuse it. Reloading, removing cache entries, loading under another module identity, or using another interpreter process can execute it again.
Is an empty initializer valid?
Yes. It declares a regular package without adding initialization behavior.
Why do framework projects import models from a models package?
They may expose model classes through one interface and ensure the relevant modules are loaded during the framework's discovery process. The requirement depends on the framework and integration: Django model discovery and Flask extensions do not share one universal rule. Keep those imports intentional and check the framework's registration lifecycle.
References: Python import system, Python modules and packages, Python logging.
Contact us
Join the community
to join the community
Try Guance
Start online and pay only for what you use.
Get startedChoose a Guance plan