The short answer for how to update Python on Mac terminal: install and upgrade Python through Homebrew (brew upgrade python) or a version manager like pyenv, and never modify whatever interpreter macOS itself relies on. Apple stopped bundling Python 2 with macOS back in 12.3, and anything living under /usr/bin or the Xcode Command Line Tools is Apple's to manage, not yours. The interpreter you develop against should be one you installed, one you can upgrade on your own schedule, and one you can point CI at so local and pipeline behavior match.
This guide walks through checking what you have, upgrading it cleanly, choosing a default, and the small hygiene steps that stop a Mac from accumulating five half-forgotten Pythons.
First, figure out what you are actually running
Open the terminal and ask:
python3 --version
which python3
The second command matters more than the first. Typical answers:
/usr/bin/python3— the stub Apple ships with the Command Line Tools. Fine for a quick script, wrong as a daily driver. You cannot upgrade it; Apple does./opt/homebrew/bin/python3(Apple silicon) or/usr/local/bin/python3(Intel) — a Homebrew install.~/.pyenv/shims/python3— pyenv is managing versions for you.
If which python3 returns the Apple path, you have not really installed Python yet — you have been borrowing it. Time to fix that.
Option 1: Homebrew, the low-ceremony route
If you just want a current interpreter and do not juggle projects pinned to different versions, Homebrew is enough:
brew install python@3.12
brew upgrade python
brew link python@3.12
brew upgrade python moves you to the newest release Homebrew packages. Two things to know before you rely on it:
- Homebrew upgrades can be aggressive. A routine
brew upgradeof something unrelated can bump your Python as a dependency, and any virtual environment built against the old version will break with a "dead interpreter" error. Rebuilding the venv (python3 -m venv .venv --clear) fixes it, but it surprises people the first time. - Homebrew intentionally does not let you
pip installinto its Python globally without a fight (externally-managed-environmenterrors under PEP 668). That is a feature: keep project dependencies in virtual environments and the interpreter stays clean.
Option 2: pyenv, the version-manager route
If you maintain more than one project — or your team pins Python per repo — pyenv is worth the extra ten minutes:
brew install pyenv
pyenv install 3.12
pyenv install 3.11
pyenv global 3.12
Add the init line to your shell profile (~/.zshrc on any recent Mac):
eval "$(pyenv init -)"
Now updating Python on the Mac terminal is just pyenv install <new-version> followed by pyenv global <new-version> — the old versions stay installed, so nothing pinned to them breaks. Per-project pinning is a one-liner that also documents intent for teammates:
cd my-service && pyenv local 3.11
That writes a .python-version file, and every shell that enters the directory silently gets the right interpreter.
Set the default Python version on macOS
Whichever route you chose, "default" just means "first match on PATH". To set the default Python version on a Mac explicitly:
- pyenv:
pyenv global 3.12— done, shims handle the rest. - Homebrew: make sure the brew bin directory precedes
/usr/binin your~/.zshrc:
export PATH="/opt/homebrew/bin:$PATH"
Then hash -r (or open a new tab) and confirm with which python3. Resist the old advice of symlinking python to python3 in /usr/local/bin by hand; version managers do it reversibly, hand-made symlinks are how machines end up in unexplainable states.
Run a script to prove the upgrade took
The five-second smoke test after any upgrade is to run a Python script on the Mac directly from the terminal:
python3 -c "import sys; print(sys.version)"
python3 myscript.py
If a project script fails right after an upgrade, the cause is almost always a virtual environment still wired to the removed interpreter. Recreate it:
python3 -m venv .venv --clear
source .venv/bin/activate
pip install -r requirements.txt
Reinstalling requirements after an interpreter bump is also the moment compiled wheels (numpy, cryptography, pydantic-core) get rebuilt for the new ABI — skipping it is where "works on my machine" stories start.
Why staying current is a security task, not a chore
Interpreter upgrades are not just about new syntax. CPython point releases regularly carry fixes for issues in modules like ssl, zipfile, and urllib that parse untrusted input, and only actively supported release lines receive those fixes at all. An interpreter that fell out of its support window keeps running your code fine — it just stops receiving patches while the advisories keep coming.
The same logic extends one layer up: the packages installed into that interpreter age faster than the interpreter itself. A dependency audit with an SCA tool catches the requests or PyYAML pin that predates a known advisory, which is the more common real-world exposure than the interpreter version. If you are still carrying anything on the 2.x line somewhere in a build image, that is a bigger problem than any of this — see our breakdown of Python 2 vs Python 3 as a security liability.
Cleaning up the graveyard
Old interpreters are attack surface and disk clutter. Once a quarter:
# Homebrew: list and remove superseded versions
brew list | grep python
brew uninstall python@3.9
# pyenv: same idea
pyenv versions
pyenv uninstall 3.9.18
Before removing anything, grep your launchd agents, cron entries, and shell profiles for hardcoded paths to the version being retired. The classic failure is a backup script pointing at /usr/local/opt/python@3.9/bin/python3 that dies silently after cleanup. Teams that want to go deeper on dependency and toolchain hygiene will find hands-on material in the Safeguard Academy.
FAQ
How do I check my Python version on macOS?
Run python3 --version in the terminal, and which python3 to see where it lives. The path tells you who manages it: /usr/bin means Apple, /opt/homebrew means Homebrew, ~/.pyenv means pyenv.
Can I update the Python that came with macOS?
No, and you should not try. The copy under /usr/bin/python3 belongs to the Xcode Command Line Tools and is updated only by Apple. Install your own interpreter with Homebrew or pyenv and put it first on PATH instead.
Homebrew or pyenv — which should I use?
Homebrew if you only ever need one current Python and want minimal setup. pyenv if you work across projects pinned to different versions, since it keeps every version installed side by side and switches per directory.
Why did my virtual environments break after updating?
A venv hardlinks to the exact interpreter that created it. When Homebrew removes that interpreter during an upgrade, the venv points at nothing. Recreate it with python3 -m venv .venv --clear and reinstall requirements — thirty seconds, fully fixed.