2.2 pyenv: Installing and Switching Python Versions
What is pyenv and Why Use It?
Python developers often work on multiple projects that require different Python versions or dependencies. Relying on a single system-wide Python installation creates conflicts, as projects may depend on features specific to a certain version. pyenv solves this problem by creating isolated, user-level Python environments. It does not modify your system Python, making it safe to use and preventing potential breakage of system tools that rely on the default Python interpreter. Instead, pyenv injects itself into your shell’s PATH, using “shims” to intercept Python-related commands (python, pip, etc.) and redirect them to the currently selected version. This allows you to change the active Python version globally, on a per-project basis, or even just for a single shell session with simple, intuitive commands.
Installing pyenv
The recommended installation method is via the pyenv-installer script. This method ensures you get the latest version along with several useful plugins, most notably pyenv-virtualenv.
Prerequisites: You must have development tools and essential libraries (like curl, git, zlib, openssl, readline, sqlite, etc.) installed. On Ubuntu/Debian, you can install these with:
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
Once prerequisites are met, run the installer:
curl https://pyenv.run | bash
The output will provide instructions for adding pyenv to your shell’s startup file (~/.bashrc, ~/.zshrc, etc.). The necessary lines typically look like this:
export PATH="$HOME/.pyenv/bin:$PATH"
eval "$(pyenv init --path)"
eval "$(pyenv virtualenv-init -bash)"
After adding these, restart your shell or source the profile file (source ~/.bashrc).
Installing a Python Version with pyenv
With pyenv installed, you can install virtually any Python version. pyenv builds Python from source, so you must have the necessary build dependencies (as listed above). To see all available versions (including unstable releases and PyPy), use pyenv install --list. To install a specific version, such as Python 3.11.5:
pyenv install 3.11.5
This command downloads the source code, compiles it, and places it in ~/.pyenv/versions/3.11.5/. The compilation process can take several minutes. If it fails, carefully review the error output; it is almost always due to a missing system library dependency.
You can also install a version and apply common optimizations during the build process by setting the PYTHON_CONFIGURE_OPTS environment variable:
PYTHON_CONFIGURE_OPTS="--enable-shared --enable-optimizations" pyenv install 3.11.5
The --enable-optimizations flag enables Profile Guided Optimization (PGO), which can result in a 10-20% performance boost but significantly increases build time.
Switching Between Versions
pyenv provides a hierarchical configuration for version selection, allowing for precise control. The priority order is:
- Shell (highest priority): Set by
PYENV_VERSIONorpyenv shell. - Local (per-project): Set by a
.python-versionfile in the current or parent directory. - Global: Set by
pyenv global. - System: The system Python (lowest priority).
To set a default version for your user account:
pyenv global 3.11.5
To set a version for a specific project directory (this creates a .python-version file):
cd my-project/
pyenv local 3.10.12
To set a version for the current shell session only:
pyenv shell 3.9.17
To see which version is currently active and how it was selected:
pyenv version
To see all installed versions (the active version is indicated with an asterisk *):
pyenv versions
The pyenv-virtualenv Plugin
The pyenv-virtualenv plugin, installed by default with the installer, integrates virtual environment management directly into pyenv. A virtual environment is an isolated directory that contains a specific Python version and its own set of packages. This is the recommended way to manage project dependencies.
To create a virtual environment based on the currently active Python version:
pyenv virtualenv my-project-env
To create a virtual environment using a specific installed Python version:
pyenv virtualenv 3.11.5 my-project-env-3.11
To activate the virtual environment for the current shell session:
pyenv activate my-project-env-3.11
To deactivate it:
pyenv deactivate
The most powerful feature is combining pyenv local with a virtualenv. This automatically activates the virtualenv whenever you cd into the project directory.
cd my-project/
pyenv local my-project-env-3.11
Now, any python or pip command in my-project/ will use the isolated environment.
Common Pitfalls and Best Practices
- Build Failures: The most common issue is missing build dependencies. Always ensure your system’s development tools and libraries are up-to-date before installing a new Python version.
- Slow Installations: Compiling Python from source is slow. For faster installations, consider using the
pyenvpluginpyenv-install-liteor pre-built binaries if available for your platform. - Stale Shims: After installing new executables (e.g., a new package provides a
cli-tool), the shims might not immediately recognize them. Runpyenv rehashto regenerate all shims. - System Python Integrity: Never use
pyenv global systemas your default. If you accidentally break a pyenv-managed version, it’s easy to fix. Breaking your system Python can cripple your OS. Use a pyenv-installed version (e.g.,3.11.5) as your global fallback. .python-versionFile: Always add.python-versionto your project’s.gitignorefile. This file is a user-specific configuration and should not be shared across a team, as others may have different version names or paths for their virtual environments. The required Python version should be defined in a more abstract way within project metadata likesetup.pyorpyproject.toml.- Combining with
pip: Always usepip installwithin an activated virtual environment. This ensures packages are installed in the correct, isolated location and not accidentally into a system-wide or user-level site-packages directory.