A Python virtual environment is an isolated directory tree that contains its own Python interpreter and packages, independent of the system-wide installation. Virtual environments prevent version conflicts between projects — for example, Project A needing Django 4.2 while Project B requires Django 5.0. The Python Packaging Authority (PyPA) recommends always using virtual environments. As of Python 3.12, venv is the built-in standard, but tools like Poetry, pyenv, and conda offer additional capabilities for dependency resolution, Python version management, and reproducible builds.
How Does venv Work?
The venv module ships with Python 3.3+ and creates a lightweight virtual environment by symlinking (or copying) the Python binary and creating an isolated site-packages directory. When activated, the shell's PATH is modified so that python and pip point to the environment's copies.
# Create a virtual environment
python3 -m venv .venv
# Activate (Linux / macOS)
source .venv/bin/activate
# Activate (Windows PowerShell)
.venv\Scripts\Activate.ps1
# Verify isolation
which python # → .venv/bin/python
pip list # → only pip and setuptools
# Deactivate
deactivateTip: Always add .venv/ to your .gitignore. The environment itself should never be committed — only the dependency specification file.
How Do You Manage Dependencies with pip?
pip is the standard package installer for Python. Use requirements.txt to pin exact versions for reproducible installs.
# Install packages
pip install requests==2.31.0 flask==3.0.0
# Freeze all installed packages (exact versions)
pip freeze > requirements.txt
# Install from requirements file
pip install -r requirements.txt
# Upgrade a package
pip install --upgrade requests
# Uninstall
pip uninstall requests# Pin exact versions for reproducibility
requests==2.31.0
flask==3.0.0
gunicorn==21.2.0
psycopg2-binary==2.9.9
# Separate dev dependencies in requirements-dev.txt
-r requirements.txt
pytest==7.4.3
black==23.12.1
mypy==1.8.0What Is pyenv and When Should You Use It?
pyenv manages multiple Python versions on a single machine. It intercepts Python commands via shims in your PATH and routes them to the correct version. Use pyenv when different projects need different Python versions (e.g., 3.10 vs 3.12).
# Install a Python version
pyenv install 3.12.1
# Set global default
pyenv global 3.12.1
# Set per-project version (creates .python-version file)
cd my-project
pyenv local 3.11.7
# List installed versions
pyenv versions
# Combine with venv
pyenv local 3.12.1
python -m venv .venv
source .venv/bin/activateHow Does Poetry Handle Virtual Environments?
Poetry is an all-in-one dependency manager that handles virtual environment creation, dependency resolution, and packaging. It uses pyproject.toml for configuration and generates a poetry.lock file for deterministic installs. Poetry automatically creates and manages virtual environments per project.
# Create a new project
poetry new my-project
# Or initialize in an existing directory
poetry init
# Add dependencies
poetry add requests flask
poetry add --group dev pytest black mypy
# Install all dependencies (creates venv automatically)
poetry install
# Run commands inside the virtual environment
poetry run python main.py
poetry run pytest
# Activate the shell
poetry shell
# Export to requirements.txt (for Docker/CI)
poetry export -f requirements.txt --output requirements.txt[tool.poetry]
name = "my-project"
version = "1.0.0"
description = "Example project"
[tool.poetry.dependencies]
python = "^3.11"
requests = "^2.31.0"
flask = "^3.0.0"
[tool.poetry.group.dev.dependencies]
pytest = "^7.4.3"
black = "^23.12.1"
mypy = "^1.8.0"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"When Should You Use conda?
conda is a cross-platform package and environment manager that handles both Python and non-Python dependencies (C libraries, CUDA, R, etc.). It is the standard in data science and machine learning because packages like NumPy and TensorFlow often depend on compiled C/Fortran libraries that pip cannot manage. Use conda when your project has non-Python binary dependencies.
# Create an environment with a specific Python version
conda create -n myenv python=3.12
# Activate
conda activate myenv
# Install packages
conda install numpy pandas scikit-learn
# Export environment
conda env export > environment.yml
# Recreate from file
conda env create -f environment.yml
# List environments
conda env list
# Remove an environment
conda env remove -n myenvHow Do These Tools Compare?
| Feature | venv + pip | Poetry | conda | pyenv |
|---|---|---|---|---|
| Python version management | No | No | Yes | Yes |
| Dependency resolution | Basic | Advanced (SAT solver) | Advanced | N/A |
| Lock file | Manual (pip freeze) | poetry.lock | environment.yml | N/A |
| Non-Python deps | No | No | Yes | No |
| Built into Python | Yes | No | No | No |
| Best for | Simple projects | Apps & libraries | Data science | Multi-version Python |
Key Takeaways
- • Always use a virtual environment — never install packages into the system Python
- • venv + pip is the zero-dependency default; use it for simple projects and scripts
- • Poetry adds proper dependency resolution and lock files — ideal for applications and libraries
- • conda is necessary when your stack includes compiled C/Fortran/CUDA dependencies
- • pyenv complements any tool above when you need multiple Python versions on one machine
- • Pin exact versions in production; use compatible-release specifiers (
~=) or caret (^) in libraries