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 yfail?" — 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?
2. Why does "from .sibling import x" fail when you run the file directly?
3. What best describes a namespace package (PEP 420)?
Flashcards
Question
Regular package
Click to reveal answer
Answer
Directory with __init__.py; its code runs once at package import and defines exports.
Question
Relative import dots
Click to reveal answer
Answer
from . = current package, from .. = parent package — resolved via __package__.
Question
Namespace package
Click to reveal answer
Answer
PEP 420 directory without __init__.py; portions across sys.path merge into one package.
Question
python -m pkg.cli
Click to reveal answer
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.