description: "Virtual Environments & Dependencies — Without a virtual environment, pip install affects your entire system (or user) Python installation. Project A…"---
08 · Virtual Environments & Dependencies¶
🎥 Video walkthrough¶
Every non-trivial Python project depends on third-party packages, and different projects on the same machine often need different, incompatible versions of them. Virtual environments solve this by giving each project its own isolated set of installed packages.
Why isolate environments¶
Without a virtual environment, pip install affects your entire system (or
user) Python installation. Project A needing requests==2.25 and Project B
needing requests==2.31 would conflict. A virtual environment gives each
project its own private copy of the interpreter's site-packages.
Creating a virtual environment¶
# create a virtual environment in a folder called .venv
python3 -m venv .venv
# activate it (macOS/Linux)
source .venv/bin/activate
# activate it (Windows, PowerShell)
.venv\Scripts\Activate.ps1
# your shell prompt now shows (.venv) — confirm which python/pip is active:
which python
which pip
While activated, python and pip refer to the versions inside .venv, not
the system ones.
Installing packages¶
pip install requests
pip install "requests>=2.31,<3.0"
pip install requests==2.31.0 # exact version — a "pin"
pip list # see everything installed in this environment
pip show requests # details about a specific package
Deactivating¶
This returns your shell to using the system/global Python.
requirements.txt¶
A requirements.txt file records exactly which packages (and versions) a
project needs, so anyone else can recreate the same environment.
Pinning strategy¶
| Style | Example | Trade-off |
|---|---|---|
| Exact pin | requests==2.31.0 |
fully reproducible, but you won't get bugfixes automatically |
| Compatible range | requests>=2.31,<3.0 |
gets patch/minor updates, avoids breaking major changes |
| Unpinned | requests |
always latest — convenient for experiments, risky for production |
For applications (not libraries you publish), exact pins in
requirements.txt are usually the safest default — they guarantee everyone
and every deployment uses identical versions.
Separating dev-only dependencies¶
It's common to split dependencies actually needed to run the app from tools only needed while developing it (test runners, linters).
# requirements.txt — needed to run the app
requests==2.31.0
click==8.1.7
# requirements-dev.txt — only needed for development
-r requirements.txt
pytest==8.2.0
black==24.4.0
Checking for outdated or vulnerable packages¶
A typical project workflow¶
mkdir my_project && cd my_project
python3 -m venv .venv
source .venv/bin/activate
pip install requests click
pip freeze > requirements.txt
echo ".venv/" >> .gitignore # never commit the virtual environment itself
git init
git add requirements.txt .gitignore
git commit -m "Initial project setup"
The .venv folder itself should never be committed to version control — it's
large, platform-specific, and fully reproducible from requirements.txt.
How It Actually Works¶
A virtual environment is mostly a directory layout plus one config file.
python3 -m venv .venv creates:
.venv/bin/python— a symlink (or small copy) pointing back at the base interpreter..venv/pyvenv.cfg— a text file recording thehome(the base Python) andinclude-system-site-packages = false..venv/lib/pythonX.Y/site-packages/— an empty install target.
The magic is in interpreter startup. When any Python starts, it walks up
from its own executable looking for a pyvenv.cfg. Finding one, it sets
sys.prefix to the venv directory and puts the venv's site-packages on
sys.path instead of the system one. So "activating" is almost cosmetic:
source .venv/bin/activate just prepends .venv/bin to $PATH and sets
$VIRTUAL_ENV, so typing python finds the venv's interpreter — which would
have used the venv's packages anyway. Running .venv/bin/python directly,
with no activation, works identically.
pip install requests then:
- Queries the PyPI "simple" index for the
requestsproject page, reads the list of released files, and picks the best-matching wheel (.whl— a ZIP with a specific naming scheme) for your Python version and platform. - Recursively resolves dependencies (
urllib3,certifi,idna,charset-normalizer), backtracking if version constraints conflict. - Downloads each wheel and unpacks it straight into
site-packages/, then writes a<pkg>.dist-info/folder containingMETADATA,RECORD(a manifest with hashes of every installed file), andentry_points.txt.
pip freeze just reads those dist-info folders and prints
name==version for each; pip install -r replays them. The .venv folder
is disposable precisely because all of this is reconstructible from
requirements.txt.
Exercise¶
Starting from an empty folder, create a virtual environment, activate it,
install requests and any one other package of your choice, generate a
requirements.txt with pip freeze, then deactivate and delete the .venv
folder entirely. Finally, recreate the environment from scratch using only
requirements.txt and confirm pip list shows the same packages.