cheat sheet
Python Installation
Install Python 3 on macOS via Homebrew or pyenv. Explains the system-Python warning, PATH precedence, and verification steps.
Python Installation — macOS
Method 1 — Homebrew (recommended for most users)
# Install Homebrew first if you haven't
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# Install Python
brew install python@3.12
Output:
==> Downloading https://ghcr.io/v2/homebrew/core/python/3.12/manifests/3.12.3
==> Fetching python@3.12
==> Installing python@3.12
...
==> Summary
🍺 /opt/homebrew/Cellar/python@3.12/3.12.3: 3,217 files, 56.7MB
Homebrew symlinks python3 and pip3 automatically. To also get python and pip (without version suffix) in your PATH:
# Add Homebrew Python to PATH (add to ~/.zshrc or ~/.bash_profile)
export PATH="$(brew --prefix python@3.12)/bin:$PATH"
Method 2 — pyenv (recommended when managing multiple versions)
brew install pyenv
# Add to ~/.zshrc
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.zshrc
echo '[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.zshrc
echo 'eval "$(pyenv init -)"' >> ~/.zshrc
source ~/.zshrc
pyenv install 3.12.3
pyenv global 3.12.3
Output:
python-build: use openssl@3 from homebrew
Downloading Python-3.12.3.tar.xz...
Installing Python-3.12.3...
Installed Python-3.12.3 to /Users/alice/.pyenv/versions/3.12.3
pyenv versions
Output:
system
* 3.12.3 (set by /Users/alice/.pyenv/version)
The system Python warning
macOS ships /usr/bin/python3 (a thin stub that prompts you to install Xcode Command Line Tools). It is managed by Apple and should not be used for development.
which python3
/usr/bin/python3 # this is the system stub
/opt/homebrew/bin/python3 # this is Homebrew Python
Never run
pip installagainst the system Python — it may interfere with macOS utilities and you cannot upgrade or remove system packages safely. Always work inside a virtual environment or use a Homebrew/pyenv-managed Python.
Verify
python3 --version
pip3 --version
which python3
Output:
Python 3.12.3
pip 24.0 from /opt/homebrew/lib/python3.12/site-packages/pip (python 3.12)
/opt/homebrew/bin/python3
Common pitfalls
PATH order matters — if
/usr/binappears before/opt/homebrew/binin your$PATH, the system stub wins. Make sure your shell config exports the Homebrew prefix early.
Check PATH order:
echo $PATH | tr ':' '\n' | grep -n python
Next steps
python3 -m venv .venv
source .venv/bin/activate
See Virtual Environments for the full guide.
Apple Silicon vs Intel — prefixes that matter
The Homebrew prefix differs between Apple Silicon (M1/M2/M3/M4) and Intel Macs, which trips up shell scripts copied from one machine to another. Always derive the prefix dynamically rather than hard-coding it.
| Machine | Homebrew prefix | Python binary |
|---|---|---|
| Apple Silicon | /opt/homebrew | /opt/homebrew/bin/python3 |
| Intel | /usr/local | /usr/local/bin/python3 |
| Rosetta 2 Intel-emulating shell on Apple Silicon | /usr/local | /usr/local/bin/python3 |
# Always use the dynamic prefix
brew --prefix
export PATH="$(brew --prefix)/bin:$PATH"
# Check what kind of CPU you're running on
sysctl -n machdep.cpu.brand_string
uname -m
# Check if your current shell is x86 or arm64
arch
file $(which python3)
Output:
/opt/homebrew
Apple M2 Pro
arm64
arm64
/opt/homebrew/bin/python3: Mach-O 64-bit executable arm64
If you have both
/opt/homebrewand/usr/localpopulated (a leftover from migrating from Intel),which -a python3will show two interpreters. They are completely separate installations — packages installed in one are invisible to the other.
Method 3 — uv python install
uv downloads a statically-linked CPython tarball (from the python-build-standalone project) and unpacks it under ~/.local/share/uv/python/. It is the fastest possible install — no Xcode Command Line Tools needed, no Homebrew dependency, no recompilation on every minor version bump.
# Install uv itself
curl -LsSf https://astral.sh/uv/install.sh | sh
exec $SHELL # reload PATH
# Install one or many Pythons
uv python install 3.12
uv python install 3.11 3.13
# List what uv can see (both uv-managed and system-installed)
uv python list
# Pin a project
cd ~/code/my-project
uv python pin 3.12
cat .python-version
Output:
Installed Python 3.12.3 in 1.27s
+ cpython-3.12.3-macos-aarch64-none (python3.12)
3.12.3
uv python installnever edits global PATH or shell config —uv run,uv venv, anduv tool runall find the right interpreter via uv's own discovery logic. If you want apythonshim on PATH, runuv tool update-shell.
Method 4 — asdf
asdf is a polyglot version manager that handles Python alongside Node, Ruby, Go, Java, and ~600 other languages via a plugin system. Its Python plugin wraps python-build (the build script behind pyenv), so the install experience is the same: source compile, slow first time, fast switches afterwards.
brew install asdf
# Wire asdf into your shell
echo -e "\n. \"$(brew --prefix asdf)/libexec/asdf.sh\"" >> ~/.zshrc
source ~/.zshrc
# Add the Python plugin and install
asdf plugin add python
asdf install python 3.12.3
asdf install python 3.13.0
# Set a global default
asdf global python 3.12.3
# Per-project pin (writes .tool-versions)
cd ~/code/my-project
asdf local python 3.13.0
cat .tool-versions
Output:
python 3.12.3 installation successful
python 3.13.0
Method 5 — mise
mise is a Rust-based successor to asdf with the same .tool-versions file format but dramatically faster shell startup (single-digit milliseconds vs ~80 ms for asdf). It also defaults to downloading precompiled Pythons via python-build rather than compiling from source on first use.
brew install mise
# Wire mise into your shell
echo 'eval "$(mise activate zsh)"' >> ~/.zshrc
source ~/.zshrc
# Install and use Python
mise use --global python@3.12
mise use python@3.13 # per-directory
# Inspect
mise ls python
mise current python
Output:
mise python@3.12.3 ✓ installed
mise ~/code/my-project: writing .tool-versions
python 3.13.0
If you are starting fresh in 2026,
miseis the better choice overasdf. Same plugin ecosystem, same config file, much faster.
Method 6 — python.org installer
The official .pkg installer from python.org is universal2 (Apple Silicon + Intel) and installs into /Library/Frameworks/Python.framework/Versions/3.12/. It is unaffected by Homebrew upgrades and remains the most reliable choice when you need a "framework build" — a Python that knows how to draw windows via the macOS GUI APIs (required by Tkinter, IDLE, and some scientific GUI tools).
# Download the latest .pkg
curl -LO https://www.python.org/ftp/python/3.12.3/python-3.12.3-macos11.pkg
# Verify the signature (optional but recommended)
pkgutil --check-signature python-3.12.3-macos11.pkg
# Install (will prompt for admin password)
sudo installer -pkg python-3.12.3-macos11.pkg -target /
# The installer creates a shim under /usr/local/bin
/usr/local/bin/python3 --version
Output:
Status: signed by a developer certificate issued by Apple for distribution
installer: Package name is Python 3.12.3
installer: Installation successful.
Python 3.12.3
The python.org installer drops an "Install Certificates.command" script under
/Applications/Python 3.12/. Run it once to populate the certificate store — without it,pip installmay fail withSSL: CERTIFICATE_VERIFY_FAILED.
Framework build vs CLT Python vs Homebrew Python
macOS has historically had several Python flavors, each linked differently against system libraries. They are not interchangeable in subtle ways.
| Flavor | Linker | Tkinter / GUI | When to use |
|---|---|---|---|
System Python stub (/usr/bin/python3) | Apple CLT | Yes (via Apple Tk) | Never — it's just a stub that triggers a CLT install |
| Xcode Command Line Tools Python | Apple CLT | Yes | Apple's internal scripts only |
Homebrew python@3.12 | Homebrew | Yes (via python-tk@3.12) | Day-to-day dev work |
| python.org framework build | Apple frameworks | Yes (uses bundled Tk) | When you need IDLE, Tkinter, or PyObjC against a stable framework |
| pyenv-built Python | OpenSSL from Homebrew | Optional (needs tcl-tk) | Multiple-version workflows |
| uv python-build-standalone | Static | Limited Tkinter | CI, ephemeral environments |
# Find every python3 on the system
ls -l /usr/bin/python3
ls -l $(brew --prefix)/bin/python3
ls -l /Library/Frameworks/Python.framework/Versions/*/bin/python3
ls -l ~/.pyenv/versions/*/bin/python3 2>/dev/null
ls -l ~/.local/share/uv/python/*/bin/python3 2>/dev/null
Output:
lrwxr-xr-x /usr/bin/python3 -> ../../Library/Developer/CommandLineTools/usr/bin/python3
lrwxr-xr-x /opt/homebrew/bin/python3 -> ../Cellar/python@3.12/3.12.3/bin/python3.12
lrwxr-xr-x /Library/Frameworks/Python.framework/Versions/3.12/bin/python3 -> python3.12
Method 7 — MacPorts
MacPorts is the older sibling to Homebrew, building everything from source by default into /opt/local/. It still has a loyal user base, particularly among people who need reproducible builds with very explicit dependencies.
# After installing MacPorts itself from https://www.macports.org/install.php
sudo port selfupdate
sudo port install python312 py312-pip py312-virtualenv
# Pick which python3 the `python3` alias points to
sudo port select --set python3 python312
sudo port select --set pip3 pip312
python3 --version
Output:
Selecting 'python312' for 'python3' succeeded
Python 3.12.3
MacPorts and Homebrew can coexist — they install into different prefixes (
/opt/localvs/opt/homebrew) — but you should not source both into the same shell. The PATH-ordering wars will eventually bite you.
Method 8 — conda / mamba / miniforge
For GPU machine learning, scientific computing, or polyglot data stacks (Python + R + Julia), the conda ecosystem manages native libraries alongside Python. On Apple Silicon, prefer Miniforge — it defaults to the community conda-forge channel (no Anaconda Inc. license risk) and has full native arm64 binaries.
# Install Miniforge for the current architecture
curl -LO "https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-$(uname)-$(uname -m).sh"
bash Miniforge3-$(uname)-$(uname -m).sh -b -p ~/miniforge3
# Initialize for zsh
~/miniforge3/bin/conda init zsh
exec $SHELL
# Create a project environment
mamba create -n ml python=3.12 numpy pandas pytorch -c pytorch
mamba activate ml
python -c "import torch; print(torch.backends.mps.is_available())"
Output:
Looking for: ['python=3.12', 'numpy', 'pandas', 'pytorch']
+ python 3.12.3-h99e199e_0
+ numpy 2.0.0
+ pandas 2.2.2
+ pytorch 2.3.0-cpu_py312
done
True
Apple Silicon's
mpsbackend (Metal Performance Shaders) is PyTorch's equivalent of CUDA.torch.backends.mps.is_available()returningTrueconfirms GPU acceleration is wired up.
Multi-version coexistence
It is normal on a working macOS dev box to have Homebrew Python, pyenv Pythons, a uv Python, and the Apple system stub all coexisting. The trick is keeping their PATH precedence stable.
# A typical mixed environment
brew list | grep python
ls ~/.pyenv/versions 2>/dev/null
uv python list
# What does `python3` resolve to right now?
which -a python3
# Make pyenv win for the current shell
eval "$(pyenv init -)"
which python3 # should be a pyenv shim
# Make Homebrew win
export PATH="$(brew --prefix)/bin:$PATH"
which python3 # should be /opt/homebrew/bin/python3
Output:
python@3.11
python@3.12
python@3.13
3.11.9
3.12.3
3.13.0
/Users/alice/.pyenv/shims/python3
/Users/alice/.pyenv/shims/python3
/opt/homebrew/bin/python3
/usr/bin/python3
/opt/homebrew/bin/python3
If you
eval "$(pyenv init -)"and prepend Homebrew's bin directory, the last one wins. Pick one strategy per shell config and stick with it.
Removing the macOS system Python warning
The first time you type python3 on a new Mac without Xcode Command Line Tools, macOS shows a GUI dialog: "The 'python3' command requires the command line developer tools." Once you install a real Python (Homebrew, pyenv, uv, etc.), the message vanishes — but only if PATH is wired correctly.
# 1. Install Homebrew Python (or any other)
brew install python@3.12
# 2. Confirm it's earlier on PATH than /usr/bin
echo $PATH | tr ':' '\n' | nl | grep -E '(homebrew|usr/bin)'
# 3. Reload the shell
exec $SHELL
# 4. The popup should never appear again
python3 -c "print('hello')"
Output:
1 /opt/homebrew/bin
2 /usr/local/bin
3 /usr/bin
hello
If you genuinely don't need Apple's Command Line Tools for anything else (no Xcode, no
git, no Homebrew formula compilations), you can leave them uninstalled and use a uv-managed Python — it has no Apple-specific build dependencies.
Verification recipes
After any install, run these to confirm the result.
# Where is python3 resolving from?
which -a python3
# Version
python3 --version
# Is pip wired to the same interpreter?
python3 -m pip --version
# Does the venv module work?
python3 -m venv /tmp/_probe && rm -rf /tmp/_probe && echo 'venv OK'
# Does SSL work?
python3 -c "import ssl; print(ssl.OPENSSL_VERSION)"
# Does Tkinter work? (GUI module that often breaks on macOS)
python3 -c "import tkinter; print(tkinter.TkVersion)"
# Can pip reach PyPI?
python3 -m pip install --dry-run requests
Output:
/opt/homebrew/bin/python3
Python 3.12.3
pip 24.0 from /opt/homebrew/lib/python3.12/site-packages/pip (python 3.12)
venv OK
OpenSSL 3.3.0 9 Apr 2024
8.6
Would install requests-2.32.3 certifi-2024.7.4 charset-normalizer-3.3.2 idna-3.7 urllib3-2.2.2
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| GUI dialog: "command line developer tools required" | No real Python on PATH | brew install python@3.12 then restart shell |
SSL: CERTIFICATE_VERIFY_FAILED | Missing cert store | python.org: run /Applications/Python 3.12/Install Certificates.command. Homebrew: pip install --upgrade certifi |
import tkinter fails | Tcl/Tk missing | brew install python-tk@3.12 for Homebrew; tcl-tk for pyenv |
pip install fails with error: Microsoft Visual C++ (yes, on macOS) | Misdiagnosed wheel platform | You're using a Windows wheel by accident — pip cache purge and reinstall |
bad CPU type in executable | Intel binary on Apple Silicon (or vice-versa) | Reinstall the package for the right arch; or use Rosetta with arch -x86_64 |
Homebrew complains about python3 already linked | Two python@3.X formulae are installed | brew unlink python@3.11 && brew link --force python@3.12 |
| pyenv refuses to build | Missing build dependencies | brew install openssl@3 readline sqlite3 xz zlib tcl-tk |
| Slow first import of Python (~2 s) | Gatekeeper checking quarantine on unsigned tarballs | xattr -dr com.apple.quarantine /opt/homebrew/Cellar/python@3.12 |
Common pitfalls (extended)
brew upgradeis destructive — Runningbrew upgradewithout arguments can move you frompython@3.12topython@3.13if both are installed. Always specify the formula:brew upgrade python@3.12. Or pin:brew pin python@3.12.
Don't
sudo brew— Homebrew refuses to run under sudo for a reason. If you seePermission denied, fix ownership:sudo chown -R $(whoami) $(brew --prefix)/Cellaronce, never use sudo again.
Tcl/Tk version mismatch — Homebrew's
python@3.12links againsttcl-tk@8, but some scientific packages expecttcl-tk@9. Ifimport tkinterworks but the window is invisible, runbrew info python-tk@3.12to see which Tk it actually linked against.
Restore a known-good shell config by stashing your
~/.zshrcand recreating it minimally: justeval "$(/opt/homebrew/bin/brew shellenv)"andeval "$(pyenv init -)"(in that order) cover 90% of cases.
Real-world recipes
Fresh Apple Silicon laptop in five commands
xcode-select --install
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
eval "$(/opt/homebrew/bin/brew shellenv)"
brew install python@3.12 git
python3 -m pip install --user uv
Lock the project to Python 3.12.3 across all team Macs
echo '3.12.3' > .python-version
echo 'python 3.12.3' > .tool-versions
# Anyone with mise / asdf / pyenv / uv on PATH will pick the right version automatically
mise install
Switch a single project between two Python versions
cd ~/code/data-pipeline
pyenv local 3.12.3 # main work
pyenv local 3.13.0 # try the latest
# Or with uv (without writing a global env)
uv venv --python 3.13
uv run pytest
Apple Silicon GPU acceleration with PyTorch
brew install miniforge
conda init zsh && exec $SHELL
mamba create -n ml python=3.12 pytorch torchvision -c pytorch
mamba activate ml
python -c "import torch; print(torch.backends.mps.is_available())"
Uninstalling cleanly
# Homebrew
brew uninstall python@3.12
# pyenv (specific version)
pyenv uninstall 3.12.3
# python.org framework build (manual)
sudo rm -rf /Library/Frameworks/Python.framework/Versions/3.12
sudo rm /usr/local/bin/python3.12 /usr/local/bin/pip3.12
# uv-managed Pythons
uv python uninstall 3.12
# Verify nothing remains
which -a python3
ls /Library/Frameworks/Python.framework/Versions/
Next steps
python3 -m venv .venv
source .venv/bin/activate
See Virtual Environments for the full guide, Homebrew for deeper coverage of the macOS package manager, and pip vs uv for the package-manager comparison.