Installing and switching between multiple Python versions on one machine with pyenv, without touching the system interpreter.
pyenv lets you install many Python versions side-by-side and choose which one is active globally, per-directory, or per-shell. It builds interpreters from source into ~/.pyenv, leaving the OS Python untouched. For security work this is invaluable: you can test whether a tool or payload behaves the same on 3.8 as on 3.12, or reproduce a target host's exact interpreter to validate an exploit.
# Install pyenv (Linux) via the official installer
curl -fsSL https://pyenv.run | bash
# Add to shell init (~/.bashrc or ~/.zshrc), then restart the shell
export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init -)"pyenv works by inserting a shims directory at the front of PATH. When you type python, the shim consults version files and dispatches to the right interpreter.
| Command | Purpose |
|---|---|
pyenv install --list |
List all installable versions |
pyenv install 3.12.4 |
Build and install a version |
pyenv versions |
Show installed versions |
pyenv global 3.12.4 |
Set the default interpreter |
pyenv local 3.11.9 |
Pin a version for the current dir (writes .python-version) |
pyenv shell 3.8.19 |
Set the version for the current shell session only |
pyenv which python |
Show which interpreter a shim resolves to |
Resolution precedence: shell > local (.python-version) > global.
# Install several versions and pin one to a project
pyenv install 3.11.9
pyenv install 3.12.4
cd ~/engagements/acme
pyenv local 3.11.9 # creates ./.python-version
python --version # Python 3.11.9Python 3.11.9
Note
Building interpreters from source needs build dependencies (build-essential, libssl-dev, libffi-dev, zlib1g-dev, etc.). Missing libs cause a broken build where modules like ssl or ctypes silently fail to import.
- Reproducing a target's exact Python version to confirm an exploit or PoC triggers before running it live.
- Compatibility-testing a tool across 3.8 – 3.13 to guarantee it will run on whatever the engagement host provides.
- Keeping an EOL interpreter (e.g. 3.7) isolated for analyzing legacy malware or client code without installing it system-wide.
- Combine
pyenvwith venvs:pyenv local 3.11.9to choose the interpreter, thenpython -m venv .venvfor package isolation (or usepyenv-virtualenv). - Commit the
.python-versionfile so teammates use the same interpreter line. - Install the build dependencies first so interpreters build with
ssl/ctypessupport. - Use
pyenvonly for versions your distro does not package; the system package is fine for the base.
- Forgetting
eval "$(pyenv init -)"in the shell rc, so the shims never take effect andpythonstays the system one. - Building without dev headers, producing an interpreter that cannot
import ssl— network tools then fail cryptically. - Confusing
pyenvversion selection with package isolation —pyenvpicks the interpreter; you still need a venv for dependencies.
Goal: install two interpreters and switch between them.
- Install
pyenvand its build deps, then restart the shell. pyenv install 3.11.9 && pyenv install 3.12.4.pyenv global 3.12.4; confirmpython --version.cdinto a project dir, runpyenv local 3.11.9, and confirmpython --versionnow reports 3.11.9 there while the parent dir still shows 3.12.4.
- [[Python-Versions]]
- [[Managing-Virtual-Environments]]
- [[Installing-Python-on-Linux]]
- [[Python-Environment-Setup/Readme|Python Environment Setup]] — module index
- [[Readme|Python for Security Professionals]] — course home