Python Virtual Environments: venv and Dependency Management
After completing this topic, you will:
Understand why virtual environments are necessary, be able to create project-specific isolated environments with venv, and know how to manage dependencies using requirements.txt.
Why are virtual environments necessary?
In Python, pip install requests installs the package globally on your system. This becomes problematic when you have two projects that require different versions of the same package.
Project A: requires requests==2.28.0
Project B: requires requests==2.31.0
System: Only one requests can be installed β Conflict!Virtual environments create independent Python environments for each project. Each project has its own set of packages, eliminating conflicts.
Project A/venv: requests==2.28.0 (isolated)
Project B/venv: requests==2.31.0 (isolated)
System Python: UnaffectedCreating and activating a venv
# Create a virtual environmentpython3 -m venv venv
# Activate (macOS/Linux)source venv/bin/activate
# Activate (Windows)venv\Scripts\activate
# The prompt changes(venv) $ python --versionPython 3.11.5In python3 -m venv venv, the second venv is the folder name. It's common to use venv or .venv.
Verify Activation
# Which Python are you using?(venv) $ which python/home/user/project/venv/bin/python
# Deactivate(venv) $ deactivate$ which python/usr/bin/python3When activated, python and pip point to the ones inside the virtual environment. Deactivating returns you to the system Python.
Installing packages within a virtual environment
(venv) $ pip install requests flask
(venv) $ pip listPackage Version---------- -------Flask 3.0.0requests 2.31.0...These packages are installed inside the venv/lib/ folder and do not affect the system Python.
requirements.txt: Recording dependencies
# Record currently installed packages(venv) $ pip freeze > requirements.txt# requirements.txt
Flask==3.0.0
Jinja2==3.1.2
MarkupSafe==2.1.3
Werkzeug==3.0.1
click==8.1.7
requests==2.31.0
urllib3==2.1.0
certifi==2023.11.17
charset-normalizer==3.3.2
idna==3.6pip freeze outputs all installed packages and their exact versions. Storing this in requirements.txt allows others (or your server) to recreate the same environment.
Installing dependencies
# Install the same packages in another environment(venv) $ pip install -r requirements.txtManually writing vs. pip freeze
# Manually written (minimal)
Flask>=3.0
requests>=2.31
# pip freeze (complete)
Flask==3.0.0
Jinja2==3.1.2
... (including all dependencies)pip freeze includes all transitive dependencies. Manually writing allows you to specify core packages and version ranges for more flexibility. Choose based on project size.
.gitignore: Don't commit the venv
# .gitignore
venv/
.venv/
__pycache__/
*.pycThe virtual environment folder should never be included in git. Reasons:
- Size: The venv folder can be tens to hundreds of MB.
- OS Dependent: A venv created on macOS might not work on Linux.
- Reproducibility: The
requirements.txtfile allows you to recreate it at any time.
# Start a project in a new environmentgit clone projectcd projectpython3 -m venv venvsource venv/bin/activatepip install -r requirements.txtReal-world workflow
# 1. Start a projectmkdir my-project && cd my-projectpython3 -m venv venvsource venv/bin/activate
# 2. Install packagespip install flask requests pandas
# 3. Develop...
# 4. Save dependenciespip freeze > requirements.txt
# 5. Git commitgit add .git commit -m "Add requirements"
# 6. Someone else checks it out and runsgit clone <repo>cd my-projectpython3 -m venv venvsource venv/bin/activatepip install -r requirements.txtpython app.pyHandling multiple Python versions
# If you have both Python 3.10 and 3.12 installed on your systempython3.10 -m venv venv310python3.12 -m venv venv312
# Each venv is tied to the Python version used when creating itsource venv310/bin/activatepython --version # Python 3.10.x
source venv312/bin/activatepython --version # Python 3.12.xvenv uses the Python version at the time of creation. If you need different Python versions for different projects, create a venv with the corresponding version.
venv vs. conda
| venv | conda | |
|---|---|---|
| Installation | Built into Python | Requires separate installation (Anaconda/Miniconda) |
| Scope | Manages only Python packages | Python + C libraries + system packages |
| Python version | Uses versions installed on the system | Also manages Python versions |
| Package source | PyPI (pip) | conda-forge + PyPI |
| Size | Lightweight (a few MB) | Heavy (several GB) |
| Recommended for | Web development, general Python | Data science, ML (NumPy/SciPy dependencies are complex) |
# conda environment creation (for comparison)conda create -n myenv python=3.11conda activate myenvconda install numpy pandas scikit-learnConda is preferred in data science because packages like NumPy and SciPy depend on C/Fortran libraries. Conda manages these binary dependencies. However, for web development or general Python projects, venv is sufficient.
Modern Dependency Management: pyproject.toml
In Python 3.11+ projects, there's a trend to use pyproject.toml instead of requirements.txt.
# pyproject.toml
[project]
name = "my-project"
version = "1.0.0"
requires-python = ">=3.10"
dependencies = [
"flask>=3.0",
"requests>=2.31",
]
[project.optional-dependencies]
dev = [
"pytest>=7.0",
"black>=23.0",
]# Install based on pyproject.tomlpip install . # Production dependenciespip install ".[dev]" # Includes development dependenciesrequirements.txt is a simple list, while pyproject.toml includes project metadata (name, version, Python version constraints). If you plan to distribute a library, pyproject.toml is the standard.
Common Mistakes
| Mistake | Result | Solution |
|---|---|---|
| Installing packages without activating the venv | Installs globally on the system | Check with which pip and install in the venv |
| Committing the venv folder to git | Bloats the repository size | Add venv/ to .gitignore |
| Not updating requirements.txt | Missing packages in other environments | Re-run pip freeze after adding/removing packages |
| Installing directly to the system Python | Causes conflicts between projects | Always work within a venv |
Confusing python and python3 | Runs the wrong Python version | Use python after activating the venv |
Key Takeaways
| Command | Role |
|---|---|
python3 -m venv venv | Create a virtual environment |
source venv/bin/activate | Activate |
deactivate | Deactivate |
pip freeze > requirements.txt | Record dependencies |
pip install -r requirements.txt | Install dependencies |
A virtual environment is "an independent Python for each project." Once you get into the habit, you'll eliminate package conflicts, the "it works on my machine" problem, and deployment environment inconsistencies. Make python3 -m venv venv the first command you run when starting a new Python project.