Modules & Packages
Packages
Organizing modules into hierarchical packages with __init__.py
Interview: Project structure — tested in system design and code organization discussions
A Python package is a directory containing modules and an __init__.py file. Packages provide a hierarchical namespace for organizing related modules. They're the standard way to structure larger Python projects and are fundamental to the Python package ecosystem.
Package Structure
- Directory with __init__.py: The directory becomes a package; __init__.py runs on package import
- Namespace packages: Python 3.3+ supports implicit namespace packages without __init__.py
- Subpackages: Nested directories with their own __init__.py create subpackages
- Import paths:
from mypackage.sub import module
__init__.py Roles
- Package marker: Tells Python this directory is a package (can be empty)
- Package initialization: Code in __init__.py runs when the package is imported
- Convenience imports: Re-export key names —
from .module import MyClasslets users dofrom package import MyClass - __all__ list: Controls what
from package import *exports
Modern Package Layout
Modern Python projects use the src/ layout: put your package inside src/mypackage/ with a pyproject.toml at the project root. This prevents import conflicts and makes testing cleaner.
Relative vs Absolute Imports
In packages, use relative imports (from . import sibling) for internal references and absolute imports (from mypackage.utils import helper) for cross-package references. PEP 8 recommends absolute imports for clarity.
Use Cases
Structuring large Python projects into logical, hierarchical packages
Creating distributable Python packages with pyproject.toml
Building internal company libraries with clean public APIs
Plugin architectures using namespace packages
Separating concerns: core logic, utilities, models, views
Common Mistakes
Putting too much logic in __init__.py — slows down imports and creates circular dependencies
Mixing relative and absolute imports inconsistently within a package
Forgetting __init__.py in subdirectories — they won't be recognized as packages (pre-3.3)
Not using src/ layout — can cause import conflicts during testing
Circular package imports — restructure or use lazy imports to fix