Modules, Imports & Packages
Python organizes code into modules (files) and packages (directories). The import system loads code once per process, caches it in sys.modules, and exposes names through the importing namespace.
Search across all documentation pages
Python organizes code into modules (files) and packages (directories). The import system loads code once per process, caches it in sys.modules, and exposes names through the importing namespace.
# myapp/services/users.py
from myapp.models.user import User
from myapp.utils.text import slugify
def list_active() -> list[User]:
return [u for u in User.all() if u.active]When to reach for this:
python -m# myapp/__init__.py
__version__ = "1.0.0"
# myapp/config.py
from dataclasses import dataclass
import os
@dataclass(frozen=True)
class Settings:
debug: bool
database_url: str
def load_settings() -> Settings:
return Settings(
debug=os.getenv("DEBUG", "0") == "1",
database_url=os.getenv("DATABASE_URL", "sqlite:///local.db"),
)
# myapp/main.py
from myapp.config import load_settings
def main() -> None:
settings = load_settings()
print(f"debug={settings.debug} db={settings.database_url}")
if __name__ == "__main__":
main()Run with: python -m myapp.main from the parent directory on PYTHONPATH.
What this demonstrates:
__init__.py can expose version metadatafrom myapp.config import ...) stay clear when package growsif __name__ == "__main__" entry guard for runnable modules-m switch sets __package__ correctly for relative imports inside the packagesys.path lists directories; PYTHONPATH and venv site-packages extend it.sys.modules.from .config import load_settings require package context (-m or package import).__init__.py can participate in a split namespace.__all__ - Documents public names for from module import * (rare in app code).project/
src/
myapp/
__init__.py
main.py
config.py
pyproject.toml
Install editable (uv pip install -e .) so import myapp resolves during development.
import importlib
def lazy_import(module: str):
return importlib.import_module(module)
# TYPE_CHECKING block avoids runtime circular import
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from myapp.models import Usera imports b while b imports a. Fix: Move shared types to a third module or lazy-import inside functions.python myapp/main.py breaks relative imports. Fix: python -m myapp.main.json.py breaks import json. Fix: Avoid stdlib names for modules.main.from utils import * pollutes namespace. Fix: Import explicit symbols.| Alternative | Use When | Don't Use When |
|---|---|---|
| Single module script | <200 lines, one author | Multiple domains emerging |
src layout package | Libraries and services | Throwaway notebook |
Lazy importlib | Optional heavy deps (torch) | Core dependency always needed |
pluggy entry points | Plugin architectures | Simple internal package |
import module binds the module object. from module import name binds the name directly into the current namespace.
Regular packages yes (or implicit namespace package without it). Empty __init__.py is fine for marking a package.
Runs a module as __main__ with correct package metadata so relative imports work.
The directory containing the script or the current directory for -m. Editable installs add src to path via metadata.
Check package on PYTHONPATH, use absolute imports, verify pyproject.toml package discovery, reinstall editable.
Possible with path hacks - discouraged. Install package editable or configure proper layout instead.
Imports for type checkers only - avoids runtime circular import while keeping hints.
One dot is current package; two dots is parent. Requires package context - not in top-level scripts.
Rarely - sometimes in __init__.py re-export APIs with explicit __all__. Never in application modules.
Multiple directories contribute to one package name without a single __init__.py - used for plugin ecosystems.
Stack versions: This page was written for Python 3.14.0 (stable 3.14, maintenance 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, and uv 0.6+.
Reviewed by Chris St. John·Last updated Jul 19, 2026