One project, one set of libraries
Projects need third-party libraries such as numpy or pandas, and different projects need different versions of them. Installing everything into one shared Python makes versions collide: upgrading for one project breaks another. A virtual environment is a private folder holding its own copy of the Python interpreter and its own installed libraries, so each project can have exactly what it needs. pip is the tool that downloads and installs libraries from the Python Package Index (PyPI) into the active environment.
# Create an environment in the project folder (once)
python -m venv .venv
# Activate it (every new terminal)
source .venv/bin/activate # macOS and Linux
.venv\Scripts\activate # Windows
# The prompt now shows (.venv); python and pip belong to it
python -c "import sys; print(sys.prefix)"
# Leave it
deactivateInstalling with pip
With the environment active, pip install numpy adds a library, pip install numpy==1.26.4 pins an exact version, pip install -U numpy upgrades it and pip uninstall numpy removes it. pip list shows what is installed. Always call it as python -m pip when unsure, which guarantees it belongs to the same Python you will run. Never use sudo pip or install into the system Python.
# Install, pin and inspect (environment active)
python -m pip install numpy pandas
python -m pip install "scipy>=1.11,<2"
python -m pip list
# Show one library
python -m pip show numpyrequirements.txt and version rules
A requirements file lists the libraries a project needs, one per line, so anyone can rebuild the environment with pip install -r requirements.txt; pip freeze > requirements.txt writes the exact installed versions. Each line is a name plus an optional version specifier: ==1.26.4 (exactly), >=2.0 (at least), <3 (below), !=2.1 (anything but) and ~=1.4.2 (compatible: at least 1.4.2 but still 1.4.x). Lines starting with # are comments. Versions compare as numbers part by part, so 1.10 is newer than 1.9, not older.
# A version is a tuple of numbers, not a string
print("1.10" > "1.9") # False (text order is wrong!)
def version_tuple(text):
return tuple(int(part) for part in text.split("."))
print(version_tuple("1.10") > version_tuple("1.9")) # True
print(version_tuple("2.0.1")) # (2, 0, 1)
# Reading one requirements line
line = "numpy>=1.26 # for arrays"
name_and_spec = line.split("#", 1)[0].strip()
print(name_and_spec) # numpy>=1.26Habits that keep projects reproducible
Create one environment per project and keep it inside the project as .venv, but do not commit it: it is large and specific to your machine. Commit requirements.txt (or pyproject.toml) instead. Write loose rules (>=) for what you need and pin exact versions (==) when you must reproduce results. If something misbehaves, you can always delete .venv and rebuild it from the requirements file in a minute.
# requirements.txt
numpy==1.26.4 # pinned: reproduce results exactly
pandas>=2.0 # at least 2.0
scipy~=1.11.0 # 1.11.x, but not 1.12
# plotting waits until we need it
# Rebuild the environment anywhere
python -m venv .venv
python -m pip install -r requirements.txt
# Record what is installed right now
python -m pip freeze > requirements.txtimport fails when you run your code. Check that the prompt shows (.venv) and that python -c "import sys; print(sys.prefix)" points inside your project before installing anything.python -m venv .venv, then activate it: one environment per project.python -m pip install name==version,pip install -r requirements.txt,pip freeze.- Specifiers:
==,>=,<,!=,~=; compare versions as tuples of numbers; commit the requirements, not.venv.
Next up: Git basics, to track every change to your code and go back when something breaks.
Lab · what's graded
- Read one requirements line with
parse_requirement25 pts - Read a whole requirements file with
parse_requirements25 pts - Make versions comparable with
version_tuple25 pts - Check a version against a rule with
satisfies25 pts