Different projects often need different Python versions. This guide covers two ways to manage Python versions on WSL Ubuntu: pyenv (recommended) for per-project version control, and update-alternatives for switching between system-installed versions.
The examples in this guide are run on WSL2 Ubuntu in Windows, but they work the same on any Ubuntu system.
Prerequisites
- WSL 2 with Ubuntu installed — see How to Install Ubuntu in WSL 2 on Windows if you need to set this up
Both methods need build dependencies for compiling Python from source. Install them first:
sudo apt update && sudo apt install -y make build-essential libssl-dev zlib1g-dev \
libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncursesw5-dev \
xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev git
Method 1: pyenv (Recommended)
pyenv lets you install any Python version and switch between them per project — without touching your system Python. It works like nvm does for Node.js.
Step 1: Install pyenv
Clone the pyenv repository and add it to your shell:
git clone https://github.com/pyenv/pyenv.git ~/.pyenv
Add pyenv to your ~/.bashrc:
echo '' >> ~/.bashrc
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc
echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(pyenv init --path)"' >> ~/.bashrc
echo 'eval "$(pyenv init -)"' >> ~/.bashrc
Load the changes:
source ~/.bashrc
Verify pyenv is working:
pyenv --version
Step 2: Install a Python Version
See what’s available:
pyenv install --list | grep "^\s*3\."
Install a version (this compiles from source, so it takes a few minutes):
pyenv install 3.12.7
Install as many versions as you need:
pyenv install 3.11.10
pyenv install 3.13.1
Step 3: Set Your Default Python Version
Set a global default that applies to all new terminal sessions:
pyenv global 3.12.7
Verify:
python --version
Step 4: Set Per-Project Python Versions
This is where pyenv really helps. Set a specific Python version for a project directory:
cd ~/projects/my-app
pyenv local 3.11.10
This creates a .python-version file in the directory. Whenever you cd into this folder, pyenv automatically switches to that version. Commit this file to your repo so your team uses the same version.
List all installed versions:
pyenv versions
Create Virtual Environments with pyenv
pyenv manages Python versions. For isolated project dependencies, add the pyenv-virtualenv plugin.
Install pyenv-virtualenv
git clone https://github.com/pyenv/pyenv-virtualenv.git $(pyenv root)/plugins/pyenv-virtualenv
echo 'eval "$(pyenv virtualenv-init -)"' >> ~/.bashrc
source ~/.bashrc
Create and Use a Virtual Environment
Create a virtualenv tied to a specific Python version:
pyenv virtualenv 3.12.7 my-project-env
Activate it manually:
pyenv activate my-project-env
Or set it as the local version for a project directory so it activates automatically:
cd ~/projects/my-app
pyenv local my-project-env
Now every time you cd into ~/projects/my-app, the virtualenv activates. When you leave the directory, it deactivates.
Method 2: update-alternatives (System-Level)
If you only need to switch between Python versions installed through apt (not per-project), update-alternatives works. This is a system-level tool built into Ubuntu.
Step 1: Install Additional Python Versions
Ubuntu only ships with one Python version. To install others, add the deadsnakes PPA:
sudo apt install -y software-properties-common
sudo add-apt-repository ppa:deadsnakes/ppa
sudo apt update
Install the versions you need:
sudo apt install -y python3.11 python3.12
Step 2: Register Versions with update-alternatives
Register each version. The number at the end is the priority — higher means it’s preferred by default:
sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.11 1
sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.12 2
Step 3: Switch Between Versions
Choose which version python3 points to:
sudo update-alternatives --config python3
You’ll see a numbered list. Enter the number of the version you want, then verify:
python3 --version
pyenv vs update-alternatives
| Feature | pyenv | update-alternatives |
|---|---|---|
| Per-project versions | Yes (.python-version) |
No (system-wide only) |
| Any Python version | Yes (compiles from source) | Only what’s in apt/PPA |
| Virtual environments | Yes (with pyenv-virtualenv) | No (use venv separately) |
| Requires sudo | No | Yes |
| Best for | Development across multiple projects | Simple system-wide default |
Useful pyenv Commands
| Command | What it does |
|---|---|
pyenv install --list |
Lists all available Python versions |
pyenv install 3.12.7 |
Installs a specific version |
pyenv global 3.12.7 |
Sets the default version |
pyenv local 3.11.10 |
Sets version for current directory |
pyenv versions |
Lists all installed versions |
pyenv uninstall 3.11.10 |
Removes a version |
pyenv which python |
Shows path to the active Python binary |
Conclusion
Use pyenv if you work on multiple projects with different Python requirements — it handles versions, per-directory switching, and virtual environments. Use update-alternatives if you just need to change the system-wide default.
For better code quality in your Python projects, check out How to Use Flake8 and Black for Python Code Quality or set up pre-commit hooks on Ubuntu WSL 2.


