Before we build the calculator from Saturday’s design, the project needs a proper home. Today was about structure and dependencies: the unglamorous part every real project depends on.
1. Where We’re Headed
The calculator will demonstrate the Open/Closed Principle: a class should be open for extension but closed for modification. We’ll build it twice, once in a way that breaks the principle and once in a way that follows it, so you can see the difference rather than take it on trust.
First, the groundwork.
2. Modules and Packages
| What it is | Example | |
|---|---|---|
| Module | Any single .py file | test.py |
| Package | A folder of modules, usually with an __init__.py | my_math/ |
project/
├── main.py
└── my_math/
├── __init__.py
├── utils.py
└── geometry/
├── __init__.py
└── utils.py
Importing:
import main_helpers # a module beside the one you're running
from my_math.utils import calculator # dot notation, through the package
from my_math.geometry import utils # a different utils.py, no clash
- Dot notation follows the folder path.
- Two modules can share a name if they live in different packages.
my_math/utils.pyandmy_math/geometry/utils.pydon’t collide.
About __init__.py: it marks a folder as a package and can run setup code when the package is imported. Since Python 3.3, a folder without one can still be imported (a “namespace package”), but add the file anyway. It makes your intent explicit and avoids confusing edge cases.
3. Two Kinds of Project
| Type | You build it to | Examples |
|---|---|---|
| Application | Run it | A CLI tool, a web app |
| Library | Let other code import it | An SDK, a framework |
4. Where Libraries Come From
- The standard library ships with Python. Modules such as
os,jsonandsqlite3are just there. - External packages live on PyPI, the Python Package Index:
boto3for AWS,FastAPI,LangChain, and hundreds of thousands more.
5. Why Virtual Environments Exist
Install everything system-wide and projects start fighting.
Project A needs version 1 of a library. Project B needs version 2. You upgrade for B, and A breaks, even though you never touched A.
A virtual environment gives each project its own private set of packages. Upgrading one project can’t break another.
Create one:
python -m venv .venv
Activate it:
| Shell | Command |
|---|---|
| Linux / Mac | source .venv/bin/activate |
| Windows, Command Prompt | .venv\Scripts\activate |
| Windows, PowerShell | .venv\Scripts\Activate.ps1 |
PowerShell blocks scripts by default. If activation fails, run this once, then try again:
Set-ExecutionPolicy -Scope CurrentUser RemoteSigned
Once it’s active, pip install puts packages inside .venv, and the system Python is untouched. Your prompt usually shows (.venv) so you know where you are.
6. Sharing a Project: requirements.txt
Never share .venv itself. It’s large, and it’s built for your operating system; it won’t work on someone else’s machine. Add it to .gitignore so it can’t be committed by accident:
.venv/
Share the list of dependencies instead:
pip freeze > requirements.txt # record what's installed
pip install -r requirements.txt # recreate it on another machine
Something to know about pip freeze: it records everything in the environment, including the dependencies of your dependencies and anything you installed to try out. That’s why the file is often longer than expected. It reproduces the environment exactly, but it doesn’t tell you which packages you actually chose.
7. pip vs uv
| pip | uv | |
|---|---|---|
| Written in | Python | Rust |
| Speed | Standard | Much faster |
| Installs packages | Yes | Yes |
| Creates virtual environments | With venv | Yes, built in |
| Installs Python itself | No | Yes |
| Records dependencies | requirements.txt | pyproject.toml plus a lockfile, uv.lock |
You’ve already used uv. The MCP and agents projects were set up with uv init and uv add, which is why they have pyproject.toml and uv.lock rather than requirements.txt. Today explained what uv was doing for you behind the scenes.
✅ Action Items
- Create a project with a package, two sub-packages and two modules that share a name. Import both from
main.py. - Make a virtual environment, activate it, install one package from PyPI, and confirm it isn’t visible from your system Python.
- Generate
requirements.txt, delete.venv, recreate it, and reinstall from the file. - Add
.venv/to.gitignore. - Do the same with uv:
uv init,uv add, and compare the files it creates with what pip gave you.
⏭️ Next up: the calculator, novice version first, inside a proper project.
