Skip to content
intermediate Phase 11 · Python Modules & Packages

Python Packages & Namespaces

Create packages with __init__.py, subpackages, and namespace packages.

45m
0 problems
Topic Progress 0%

Regular Packages and __init__.py

Regular Packages and init.py

A directory becomes a regular package when it contains __init__.py (an empty file suffices). Importing mypkg executes that file once, and whatever it binds becomes the package's attribute surface — re-exporting keeps call sites short.

mypkg/
├── __init__.py      # from .core import solve
├── core.py
└── utils/
    ├── __init__.py  # subpackage marker
    └── text.py

Subdirectories without __init__.py are not classic packages; since Python 3.3 they can still import as namespace packages, which behave differently when two directories on sys.path share the same name.

Absolute and Relative Imports

Absolute and Relative Imports

Inside mypkg/utils/text.py, choose one style and stay consistent:

from mypkg.core import solve      # absolute: starts from a top-level package
from ..core import solve          # relative: one dot = current package, two = parent
from . import helpers              # sibling module in the same package

Relative dots resolve against __package__, which Python sets only when the module was imported as part of a package. Running a file directly (python text.py) leaves __package__ as None, so relative imports raise ImportError. That is why executables live at the project root or behind python -m mypkg.cli.

Namespace Packages and Failure Modes

Namespace Packages and Failure Modes

PEP 420 dropped the __init__.py requirement: a plain directory found on sys.path becomes a namespace package, and portions with the same name across multiple paths are merged. Plugins and split distributions use this intentionally; accidental use causes confusion because dir(mypkg) shows fragments assembled from several locations and tooling cannot find a single package root.

Interview traps:

  • "Why does from .x import y fail?" — the file was executed as a script, so there is no parent package.
  • "Namespace or regular package?" — regular when you need __init__ side effects and a single root; namespace when one logical package spans several directories.

Quiz

1. What does __init__.py primarily do in a regular package?

Question 1 options

2. Why does "from .sibling import x" fail when you run the file directly?

Question 2 options

3. What best describes a namespace package (PEP 420)?

Question 3 options

Flashcards

Question

Regular package

Answer

Directory with __init__.py; its code runs once at package import and defines exports.

Question

Relative import dots

Answer

from . = current package, from .. = parent package — resolved via __package__.

Question

Namespace package

Answer

PEP 420 directory without __init__.py; portions across sys.path merge into one package.

Question

python -m pkg.cli

Answer

Runs a package entry point with correct package context so relative imports work.

Revision Notes

Key Takeaways

  • 1. __init__.py marks a regular package and is the place to re-export a stable API
  • 2. Relative imports require import-time package context — use python -m, not direct file execution
  • 3. Namespace packages merge directories across sys.path and are powerful but easy to trigger accidentally

Interview Tips

  • • Name the exact error (attempted relative import with no known parent package) and its cause before proposing the fix
  • • Justify regular versus namespace packaging by how the code is executed and distributed

Cheat Sheet

pkg = dir + init.py; from .sib / from ..pkg relative via package; PEP 420 namespace = no init.py; run entry points with python -m.

Continue Learning