How do I write good/correct package __init__.py files
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.
Introduction
An __init__.py file marks a directory as a Python package and controls what gets imported when someone uses from mypackage import .... A good __init__.py does three things: defines __all__ to control from package import *, re-exports the public API for convenient access, and stays minimal (no heavy computation). In Python 3.3+, __init__.py is optional for namespace packages, but explicit packages with __init__.py are still the standard for most projects.
Minimal init.py
The simplest valid __init__.py is an empty file:
Re-Exporting the Public API
A well-designed __init__.py re-exports key symbols so users do not need to know the internal module structure:
Defining all
__all__ controls what from package import * exports:
Without __all__, from package import * exports everything that does not start with _.
Package with Subpackages
Lazy Imports for Performance
If your package has expensive imports, defer them:
This pattern (PEP 562) works in Python 3.7+.
Version and Metadata
Real-World Examples
Flask-style
requests-style
What NOT to Put in init.py
Common Pitfalls
- Importing everything with
from submodule import *in__init__.py: This pollutes the package namespace with every symbol from every submodule. Name collisions are silent — a later import overwrites an earlier one. Import only the public API explicitly. - Running expensive code at import time: Database connections, file reads, or network requests in
__init__.pyslow down every import of the package. Use lazy imports with__getattr__or move initialization to an explicitinit()function. - Circular imports between
__init__.pyand submodules: If__init__.pyimports frommodule_a, andmodule_aimports frommypackage(which triggers__init__.pyagain), you getImportErroror partially initialized modules. Break the cycle by importing at function scope or restructuring. - Not defining
__all__: Without__all__,from package import *exports everything in the namespace, including re-imported standard library modules and private helpers. Always define__all__to control the public API. - Creating a namespace conflict with the package name: If
mypackage/__init__.pydefinesmypackage = "something", it shadows the package itself. Avoid defining variables or functions with the same name as the package.
Summary
- Use
__init__.pyto define the package's public API by re-exporting key symbols - Always define
__all__to controlfrom package import *behavior - Keep
__init__.pyminimal — no heavy computation, no side effects - Use
__getattr__(Python 3.7+) for lazy imports of expensive modules - Import specific names, never
from submodule import *, to avoid namespace pollution
Related reading
- How do I write JSON data to a file?
- How do Python dictionary hash lookups work?
- How do Python functions handle the types of parameters that you pass in?
- How do Python's any and all functions work?
- How do threads work in Python, and what are common Python-threading specific pitfalls?
- How do we determine the number of days for a given month in python
- How do you access the query string in Flask routes?
- How do you add a Dictionary of items into another Dictionary
.png&w=3840&q=75)
Tackling System Design Interview Problems
A short course that equips you with the skills to approach system design interviews methodically.
Start the free courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.