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:
pyenvenables 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 by | Official | Community | Community |
| Managed objects | Compiler & toolchain | Python interpreter versions | Ruby interpreter |
| Version switching | Toolchain-level | Interpreter-level | Interpreter-level |
| Isolation mechanism | Toolchain isolation | With venv / pyenv-virtualenv | With gemset or plugins |
| Path mechanism | ~/.cargo/bin shim | PATH shim + env vars | PATH shim + env vars |
| Cross-platform | macOS / Linux / Windows | macOS / Linux / WSL | macOS / Linux |
| Package management | Built-in cargo | With pip / poetry | With 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:
- The shell first resolves to
~/.pyenv/shims/python(intercepted by the shim layer) - 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