Modules & Packages — The Complete Notebook
Comprehensive guide on Modules & Packages — The Complete Notebook.
Modules & Packages
1. Overview#
As a program grows past a single file, you need a way to organize code into reusable units. Python calls a single .py file a module, and a directory of related modules a package. This note also covers pip and virtual environments — the tools that manage which packages are installed and where.
2. Modules#
2.1 Creating and Importing a Module#
🐍 PythonInteractive WebAssembly# file: math_utils.py
def add(a, b):
return a + b
def multiply(a, b):
return a * b
PI = 3.14159
🐍 PythonInteractive WebAssembly# file: main.py
import math_utils
print(math_utils.add(2, 3)) # 5
print(math_utils.PI) # 3.14159
2.2 Import Variants#
🐍 PythonInteractive WebAssemblyimport math_utils # import whole module, access via math_utils.add()
from math_utils import add # import a specific name directly
from math_utils import add, multiply # import multiple names
from math_utils import add as sum_two # rename on import
import math_utils as mu # rename the module itself
from math_utils import * # import everything (avoid — pollutes namespace)
Avoid
from module import *in real projects — it makes it unclear where a name came from and can silently overwrite existing names.
2.3 if __name__ == "__main__":#
This lets a file work both as a standalone script and as an importable module.
🐍 PythonInteractive WebAssembly# file: math_utils.py
def add(a, b):
return a + b
if __name__ == "__main__":
# Only runs when this file is executed directly (python math_utils.py)
# Does NOT run when imported elsewhere
print(add(2, 3))
2.4 Module Search Path#
Python looks for modules in this order: the current script's directory → PYTHONPATH env variable → the standard library → installed site-packages.
🐍 PythonInteractive WebAssemblyimport sys
print(sys.path) # list of directories Python searches, in order
3. Packages#
3.1 Basic Package Structure#
codemy_project/ ├── main.py └── utils/ ├── __init__.py ├── math_ops.py └── string_ops.py
🐍 PythonInteractive WebAssembly# utils/math_ops.py
def add(a, b):
return a + b
🐍 PythonInteractive WebAssembly# main.py
from utils.math_ops import add
print(add(2, 3))
3.2 The Role of __init__.py#
An __init__.py file marks a directory as a package and runs when the package is first imported. It can also be used to control what's exposed at the package level.
🐍 PythonInteractive WebAssembly# utils/__init__.py
from .math_ops import add
from .string_ops import capitalize_words
# Now callers can do:
# from utils import add, capitalize_words
# instead of:
# from utils.math_ops import add
Since Python 3.3,
__init__.pyis technically optional for "namespace packages," but it's still standard practice to include one — it makes the package's public API explicit and works reliably everywhere.
3.3 Relative vs Absolute Imports#
🐍 PythonInteractive WebAssembly# Absolute import — preferred, unambiguous
from utils.math_ops import add
# Relative import — used *inside* a package, relative to the current module
from .math_ops import add # same package
from ..shared import constants # parent package
4. Virtual Environments#
A virtual environment is an isolated Python installation for a single project — so its dependencies don't clash with other projects or the system Python.
4.1 Creating and Activating#
bash# Create a virtual environment named "venv"
python -m venv venv
# Activate it
source venv/bin/activate # macOS/Linux
venv\Scripts\activate # Windows
# Deactivate when done
deactivate
Once activated,
pythonandpippoint to the environment's isolated copies — packages installed here won't affect your global Python installation.
4.2 Confirming You're in the Right Environment#
bashwhich python # macOS/Linux — should point inside venv/
python -m pip --version
5. pip — The Package Installer#
5.1 Common Commands#
bashpip install requests # install a package
pip install requests==2.31.0 # install a specific version
pip install --upgrade requests # upgrade an installed package
pip uninstall requests # remove a package
pip list # list installed packages
pip show requests # details about one package
5.2 requirements.txt — Reproducible Environments#
bashpip freeze > requirements.txt # snapshot current environment
pip install -r requirements.txt # recreate it elsewhere
Mathematical Formulation# requirements.txt requests==2.31.0 fastapi==0.111.0 pydantic>=2.0,<3.0
5.3 Modern Alternative: pyproject.toml#
Newer projects increasingly define dependencies in pyproject.toml (used by tools like poetry and pip itself) instead of requirements.txt. This is covered in detail in packaging-deployment.md.
6. Common Pitfalls#
INCORRECT: Circular Imports#
🐍 PythonInteractive WebAssembly# module_a.py
from module_b import func_b
def func_a():
return func_b()
🐍 PythonInteractive WebAssembly# module_b.py
from module_a import func_a # ImportError: circular dependency
def func_b():
return func_a()
CORRECT: Fix — Restructure or Import Inside the Function#
🐍 PythonInteractive WebAssembly# module_b.py
def func_b():
from module_a import func_a # deferred import, avoids the circular load at import time
return func_a()
INCORRECT: Installing Packages Globally Instead of in a Virtual Environment#
Leads to version conflicts between unrelated projects on the same machine — always work inside an activated virtual environment.
7. Summary & Best Practices Checklist#
- One virtual environment per project — never install project dependencies globally.
- Keep
requirements.txt(orpyproject.toml) up to date and committed to version control. - Use absolute imports for clarity; reserve relative imports for internal package structure.
- Avoid
from module import *in production code. - Use
__init__.pyto define a clean public API for your package. - Watch for circular imports when two modules depend on each other — restructure if it happens.
Modules & Package Architecture Checkpoint
Finished studying this notebook?
Mark this guide as completed to update your course progress roadmap.