This post is a personal Python environment configuration cheatsheet.

Origin: Real Python – Managing Multiple Python Versions with pyenv

Platforms: macOS / Linux / WSL

What and Why

pyenv is a lightweight Python version management tool that allows users to switch between different Python versions.

Modern languages like Rust use the official tool rustup for version management, while pyenv is a third-party maintained project. It was developed with reference to Ruby's rbenv and ruby-build as a Python version control tool.

pyenv solves the problem of managing multiple Python versions on a single machine. It can also be combined with virtual environments (such as venv or pyenv-virtualenv) to achieve project-level dependency isolation, preventing package pollution and conflicts.

Understanding the Benefits of pyenv

TL;DR: pyenv enables flexible management of multiple Python versions (both Python 2 and 3) on a single machine. It ensures proper isolation between projects with virtual environments setting.

pyenv is specifically designed for cleanly managing multiple Python versions. Even if your OS system already comes with Python preinstalled, using pyenv is still highly recommended. It keeps the system Python clean/untouched and allows you to work with multiple projects requiring different Python versions.

Q: Why not use the system Python in daily?

System Python is installed and managed directly by the operating system.

On macOS and Linux, a default Python is usually preinstalled; on Windows, it typically requires manual installation.

You can think of system Python as “belonging to the OS“.

In many cases, system components depend on this specific Python version to function correctly. Modifying it by upgrading/downgrading or installing packages may break system functionality and lead to critical crash.

Additionally, you often have limited control over the system preinstalled Python version.

For example, on Ubuntu, the Python version in official repositories may be outdated. You might have to wait for a new OS release to get a newer Python version.

If you install third-party packages globally using pip, they are added to the system-wide environment. This creates conflicts when different projects require different versions of the same package.

In many systems, installing Python versions or global packages requires administrator privileges. It is inconvenient especially in restricted enterprise environments.

In summary, using system Python directly has several drawbacks:

  • Potentially breaking the operating system
  • Inability to use the latest Python versions and features
  • Compatibility issues with projects requiring older versions
  • Inability to develop projects requiring newer features
  • Dependency installation may require admin intervention

✅ Ideal solution: flexible and safe Python environment management

An ideal Python setup should allow you to:

  • Install Python in user space (no admin privileges required)
  • Freely install, manage, and uninstall multiple Python versions
  • Specify exact Python versions per project
  • Switch between versions at any time

pyenv provides all of these capabilities. It also supports installing pre-release versions of Python, allowing you to test new features and compatibility in advance.


Comparison of Version Management Tools

Feature🦀 Rust – rustup🐍 Python – pyenv💎 Ruby – rbenv
Maintained byOfficialCommunityCommunity
Managed objectsCompiler & toolchainPython interpreter versionsRuby interpreter
Version switchingToolchain-levelInterpreter-levelInterpreter-level
Isolation mechanismToolchain isolationWith venv / pyenv-virtualenvWith gemset or plugins
Path mechanism~/.cargo/bin shimPATH shim + env varsPATH shim + env vars
Cross-platformmacOS / Linux / WindowsmacOS / Linux / WSLmacOS / Linux
Package managementBuilt-in cargoWith pip / poetryWith bundler

(Adapted from GPT5 answers)

Installing pyenv

Refer to: Installation of pyenv | GitHub

For macOS users, use Homebrew and brew command:

brew update
brew install pyenv

After installation, add the following to your ~/.zshrc or ~/.zprofile (for bash, use ~/.bashrc or ~/.bash_profile):

export PYENV_ROOT="$HOME/.pyenv"
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init - zsh)"
# or
# eval "$(pyenv init - bash)"

Core Mechanism

pyenv uses a "shim layer" to manage versions. When running python or pip commands in the shell:

  1. The shell first resolves to ~/.pyenv/shims/python (intercepted by the shim layer)
  2. The shim forwards the command to the appropriate interpreter based on your configuration (global / local / shell)

You can verify this behavior using which python and pyenv which python:

which python
# /Users/user_name/.pyenv/shims/python

pyenv which python
# /Users/user_name/.pyenv/versions/3.14.0/bin/python

Installing and Switching Python Versions

Listing available versions:

pyenv install --list

Install specific versions:

pyenv install 3.12.3
pyenv install 3.14.0

Set the global version (affects all shells) .python-version. This file is located in ~/.pyenv:

pyenv global 3.14.0

Set the local version (only affects the current directory) .python-version in the current directory:

pyenv local 3.12.3

Virtual Environments with pyenv-virtualenv

On macOS, virtual environments created via python -m venv may sometimes behave unexpectedly due to pyenv’s shim layer. It is recommended to use pyenv and together with pyenv-virtualenv for consistent management.

Install pyenv-virtualenv:

brew install pyenv-virtualenv

Add the following initialization to your shell config (~/.zshrc for zsh, ~/.bashrc for bash):

eval "$(pyenv virtualenv-init - zsh)"
# or
# eval "$(pyenv virtualenv-init - bash)"

Create a virtual environment (based on Python 3.14.0, named venv-name):

pyenv virtualenv 3.14.0 venv-name

Unlike python -m venv .venv, virtual environments are not created in the current directory. Instead, pyenv manages them in ~/.pyenv:

List installed versions and environments (or use pyenv virtualenvs):

pyenv versions
  system
  3.9.24
  3.12.12
* 3.14.0 (set by /Users/user_name/.pyenv/version)
  3.14.0/envs/venv-name
  venv-name --> /Users/user_name/.pyenv/versions/3.14.0/envs/venv-name

Activate and deactivate environments:

pyenv activate venv-name
pyenv deactivate

Verifying the Interpreter Used by a Virtual Environment

Running which python will always return the path intercepted by the shim layer, i.e. the location of shim/python:

which python
# /Users/user_name/.pyenv/shims/python

The correct way is running pyenv which python. Display the full path to an executable:

pyenv which python
# /Users/user_name/.pyenv/versions/env_name/bin/python

Further Reading

pyenv GitHub Repository

Managing Multiple Python Versions With pyenv