Package Structure
A package is just a directory with __init__.py. Sub-packages are nested directories, each with their own __init__.py.
# Project structure:
# myproject/
# __init__.py
# math_utils.py
# string_utils.py
# data/
# __init__.py
# loader.py
# Importing from the package:
from myproject import math_utils
from myproject.data import loader
from myproject.string_utils import clean_textThe __init__.py File
__init__.py runs when the package is imported. Use it to expose the package's public API.
# myproject/__init__.py
from .math_utils import add, subtract
from .string_utils import clean_text
__version__ = "1.0.0"
__all__ = ["add", "subtract", "clean_text"]
# Now users can do:
# from myproject import add (instead of myproject.math_utils.add)Installing Third-Party Packages with pip
pip is Python's package manager. Install packages from PyPI (Python Package Index).
# Install a package
# pip install requests
# Install specific version
# pip install requests==2.31.0
# Install from requirements file
# pip install -r requirements.txt
# List installed packages
# pip list
# Save current environment to file
# pip freeze > requirements.txtAlways use a virtual environment before pip installing packages for a project.
requirements.txt – Reproducible Environments
Share your project's dependencies so others can install exactly the same versions.
# requirements.txt
requests==2.31.0
flask==3.0.0
pandas>=2.0.0
numpy>=1.24.0
python-dotenv==1.0.0
# Install all at once:
# pip install -r requirements.txtRelative vs Absolute Imports
Inside a package, use relative imports (dot notation) to reference sibling modules.
# Inside myproject/math_utils.py:
from . import string_utils # Sibling module
from .data.loader import read_csv # Sub-package
from myproject.config import DEBUG # Absolute importPackages: Organizing Modules Into a Tree
A module is one .py file; a package is a directory of modules. Packages let you group related code and import it with dotted paths, keeping large projects navigable.
myapp/
├── __init__.py # marks the dir as a package
├── models/
│ ├── __init__.py
│ └── user.py # → from myapp.models.user import User
└── utils/
├── __init__.py
└── dates.py
from myapp.models.user import User # absolute import (preferred)
from ..utils.dates import format_date # relative import (within package)
| Term | Is |
|---|---|
| module | a single .py file |
| package | a folder of modules |
| PyPI package | third-party code installed via pip |
The __init__.py file marks a directory as a package (it can be empty, or expose a curated public API by importing key names). Absolute vs relative imports: prefer absolute (from myapp.models.user import User) — they're clearer and don't break when you move files; use relative (from ..utils import x) sparingly within a package. Two "package" meanings: your own directory-packages, and distributable packages you pip install from PyPI — the latter add a pyproject.toml describing metadata and dependencies so others can install your code.
🏋️ Practical Exercise
Build and use packages:
- Create a folder with an
__init__.pyand two module files inside it. - Import a function from one of those modules using the package path.
- Install a third-party package with
pip install requestsand import it. - Freeze your dependencies with
pip freeze > requirements.txt.
🔥 Challenge Exercise
Structure a small project as a package: a top-level package directory with an __init__.py, a utils subpackage, and a couple of modules. Import across modules using both absolute and relative imports, and expose a clean public API by importing key names in the package’s __init__.py. Create a requirements.txt listing one third-party dependency and explain how someone would reproduce your environment.
📋 Summary
- A package is a directory of modules grouped under a common namespace.
__init__.pymarks a directory as a package and can expose a curated public API.- Absolute imports use the full path from the project root; relative imports use leading dots (
from . import x). pipinstalls third-party packages from the Python Package Index (PyPI).requirements.txtpins dependencies so environments are reproducible.- Generate it with
pip freeze > requirements.txtand install withpip install -r requirements.txt.
Interview Questions on Packages
- What is a package and how is it different from a module?
- What is the role of the
__init__.pyfile? - What is the difference between absolute and relative imports?
- What does
pipdo? - What is the purpose of
requirements.txt? - How do you generate a
requirements.txtfile? - What is a namespace package?
Related Topics
FAQ
__init__.py in modern Python? +Not strictly — Python 3.3+ supports namespace packages without it. But including an __init__.py is still recommended: it makes the package explicit and gives you a place to define package-level imports and the public API.
Absolute imports spell out the full path from the project root (from myapp.utils import helper). Relative imports use dots relative to the current package (from .utils import helper). Absolute imports are generally clearer and preferred.
pip freeze produce? +It lists every installed package and its exact version. Redirecting it to requirements.txt captures a snapshot so others can recreate the same environment with pip install -r requirements.txt.
Into the active Python environment’s site-packages. Inside a virtual environment that is the project-local folder; otherwise it is the global interpreter — which is why virtual environments are recommended.

