Nearly every confusing Python bug report — "works on my machine", pip install clobbering unrelated packages, a script silently using the wrong
interpreter — traces back to skipping two habits: managing Python versions
explicitly, and never installing packages outside a virtual environment.
This guide sets both up.
Don't use the system Python
macOS and most Linux distros ship a Python for their own internal tooling.
It's tempting to pip install straight into it, but that's exactly how you
end up breaking OS scripts or fighting permission errors. Treat the system
Python as off-limits and manage your own versions with pyenv.
Install pyenv
macOS:
brew install pyenvLinux:
curl https://pyenv.run | bashEither way, add this to your ~/.zshrc or ~/.bashrc:
export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init -)"Restart your terminal and confirm:
pyenv --versionWindows users: use pyenv-win, or better, run this whole guide inside WSL2 — the Python tooling ecosystem assumes a POSIX shell almost as universally as the Node ecosystem does.
On Linux, pyenv builds Python from source, so it needs build tools and
headers installed first (build-essential, libssl-dev, zlib1g-dev,
and a handful of others — the pyenv wiki's "suggested
build environment"
page has the exact list per distro). Skipping this step is the single most
common pyenv install failure.
Install a Python version
pyenv install 3.12
pyenv global 3.12Verify:
python --version
pip --versionPin the version per project
Inside a project directory:
pyenv local 3.12This drops a .python-version file, which pyenv reads automatically —
cd into that directory and python resolves to 3.12 without touching
your global setting.
Always use a virtual environment
A virtual environment gives each project its own isolated set of installed
packages, so pip install in one project can never break another. The
built-in venv module is enough for most projects:
python -m venv .venv
source .venv/bin/activateYour shell prompt will show (.venv) while it's active. Install project
dependencies inside the activated environment:
pip install -r requirements.txtFreeze what's installed back into that file as you add packages:
pip freeze > requirements.txtDeactivate when you're done:
deactivateIf a project's dependency list is growing complex — version conflicts,
dev-only vs. production dependencies, lockfiles — look at
Poetry or uv
instead of hand-managing requirements.txt. Both wrap pyenv-style version
management and virtual envs into one tool with a lockfile, similar to what
package-lock.json does for Node.
Common gotchas
pyenv install 3.12 fails partway through compiling. This is almost
always a missing build dependency (see the callout above), not a pyenv bug.
Read the actual error near the top of the output — it usually names the
missing library directly.
python still resolves to /usr/bin/python3 after installing pyenv.
The eval "$(pyenv init -)" line has to run after your PATH is set, and
it has to actually be in the shell config file your terminal loads. Run
type python — if it doesn't point into ~/.pyenv/shims/python, the init
line isn't taking effect.
Once pyenv and a virtual environment are both second nature, "it works on my machine" stops being a Python problem — every project carries its own exact interpreter version and dependency set with it.