Python 3.12 · macOS Guide

Python
on Mac

A complete, practical reference for Macintosh users learning Python from scratch. Covers installation on macOS, every core language concept, and real syntax you can run in Terminal today.

Python 3.12 macOS Ventura / Sonoma / Sequoia Terminal · Homebrew · pyenv VS Code · Xcode Tools 12 Language Sections

Setting Up Python on Your Mac

macOS ships with a legacy Python 2.7 for internal use — never use it for your own code. Follow these four steps to install a proper, modern Python environment. Takes about 10 minutes.

Terminal Homebrew pyenv VS Code Xcode Command Line Tools
Step 1

Open Terminal

Press Space, type Terminal, press . Or find it in Applications → Utilities → Terminal. This is where you run all Python commands.

Step 2

Xcode Tools

These are Apple's free developer command-line tools — required by Homebrew and pyenv. Run the command in the terminal below. A dialog will appear; click Install.

Step 3

Install Homebrew

Homebrew is the standard package manager for Mac. It lets you install Python, Git, and thousands of developer tools with a single command from brew.sh.

Step 4

Install Python

Use pyenv to manage Python versions (strongly recommended over installing Python directly). This lets you switch between versions and keeps your system Python untouched.

Terminal — zsh — 80×24
Step 1 — Check what Python your Mac has (don't use this one)
% python3 --version
Python 3.9.6 ← Apple's built-in; outdated, do not use
Step 2 — Install Xcode Command Line Tools
% xcode-select --install
xcode-select: note: install requested for command line developer tools
# A dialog opens. Click "Install". Takes ~5 min on first Mac setup.
Step 3 — Install Homebrew (the Mac package manager)
% /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
==> Homebrew is installed and ready to brew!
# Apple Silicon (M1/M2/M3/M4)? Homebrew installs to /opt/homebrew
# Intel Mac? It installs to /usr/local. Follow any PATH instructions shown.
Step 4a — Install pyenv (Python version manager)
% brew install pyenv
# After install, add pyenv to your shell. For zsh (default on modern Mac):
% echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.zshrc
% echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.zshrc
% echo 'eval "$(pyenv init -)"' >> ~/.zshrc
% source ~/.zshrc
Step 4b — Install Python 3.12 via pyenv
% pyenv install 3.12.3
Downloading Python-3.12.3.tar.xz...
% pyenv global 3.12.3 # make it the default everywhere
% python --version
Python 3.12.3 ✓
Step 5 — Install VS Code (recommended editor)
% brew install --cask visual-studio-code
# Then in VS Code: Cmd+Shift+X → search "Python" → install Microsoft Python extension
# Cmd+Shift+P → "Python: Select Interpreter" → choose your pyenv Python
Step 6 — Create your first project folder
% mkdir ~/PythonProjects && cd ~/PythonProjects
% python -m venv .venv # create virtual environment
% source .venv/bin/activate # activate it (prompt changes to (.venv))
(.venv) % ← you're now inside the virtual env
🍎 Apple Silicon (M1 / M2 / M3 / M4) note: If you see architecture-related errors during install, you may need to run arch -x86_64 brew install ... for some packages. The steps above work natively on ARM — no Rosetta needed for Python.
Never run sudo pip install on a Mac. It modifies the system Python and can break macOS tools. Always use a virtual environment (python -m venv .venv) and activate it first.

Essential Terminal Commands

CommandWhat it does
pwdPrint working directory — shows where you are
lsList files in current directory
cd ~/PythonProjectsChange to your projects folder
mkdir myappCreate a new directory
python script.pyRun a Python script
pythonOpen the interactive Python REPL
pip install requestsInstall a package
pip listShow installed packages
⌃ CStop a running program
⌃ DExit the Python REPL
Mac keyboard in Terminal: The Command key does not work in Terminal the way it does in apps. Use Control for terminal shortcuts like C to stop a program.
mac_useful_commands.sh
0

Hello, World!

Your first Python program. Then a slightly expanded version that shows the building blocks you'll use constantly — variables, f-strings, user input, and a function.

print() variables f-strings input() def

The simplest program

Python's print() function outputs text to the terminal. That's it — no curly braces, no semicolons, no main() required for small scripts.

Variables

No var, let, or int keyword. Just write name = value. Python infers the type dynamically.

f-strings (Python 3.6+)

Prefix a string with f and embed expressions directly: f"Hello, {name}!". The {...} is evaluated at runtime. This is the preferred way to format strings in modern Python.

Running on your Mac

Save the file as hello.py, then in Terminal:

In Terminal:
cd ~/PythonProjects
python hello.py

The interactive REPL

Type python in Terminal to open the REPL (Read-Eval-Print Loop). Try expressions line by line. Exit with D or type exit().

hello.py
01

Basics & Syntax

Python uses indentation (4 spaces) instead of braces to define blocks. There are no semicolons. It is dynamically but strongly typed — "1" + 1 raises a TypeError, unlike JavaScript.

indentation variables operators strings f-strings comments

Indentation is syntax

Python uses 4 spaces per level. Tabs vs spaces is a hard error if mixed. VS Code handles this automatically — check the bottom-right corner shows "Spaces: 4".

Comments

# single line — everything after # is ignored. There are no multi-line block comments; use consecutive # lines. Triple-quoted strings """...""" are used as docstrings (function/class documentation), not general comments.

Operators — differences from other languages

  • //Floor (integer) division: 7 // 2 → 3. Plain / always returns a float.
  • **Exponentiation: 2 ** 8 → 256. Not ^ (which is XOR in Python).
  • and/orLogical operators are words, not && and ||.
  • notLogical negation — a word, not !.
  • isIdentity check (same object). Use only for None, True, False.
  • inMembership: "a" in ["a","b"] → True.

String literals

  • '...'Single quotes — identical to double quotes.
  • "..."Double quotes — use whichever avoids escaping apostrophes.
  • """..."""Triple quotes — spans multiple lines. Used for docstrings.
  • r"..."Raw string — backslashes are literal. Use for file paths and regex.
  • f"..."F-string — embeds expressions. f"Pi is {3.14:.2f}"
Mac file paths: On macOS, paths use forward slashes: /Users/alice/Documents. Use Python's pathlib.Path or raw strings to avoid escaping issues: Path.home() / "Documents"
01_basics.py
02

Built-in Types

Python's type system is dynamic — a variable can hold any type at any time. But Python is strongly typed: operations on incompatible types raise errors rather than silently coercing them.

int float bool str type() isinstance() type hints None truthiness

Numeric types

intArbitrary precision. 42, -7, 1_000_000 (underscores OK). floatIEEE 754 double. 3.14, 1e-10, float('inf'). boolSubclass of int. True == 1, False == 0. Capitalised. complex3 + 2j. Rare in everyday code.

Type inspection

Use type(x) to check type. Prefer isinstance(x, int) for conditional checks — it handles subclasses.

Type hints (Python 3.5+)

Hints are optional documentation. The interpreter does not enforce them. Tools like mypy and VS Code use them for static analysis and autocomplete.

def greet(name: str) -> str:

age: int = 30

Truthiness — what is falsy?

In Python, every value has a boolean interpretation. These are falsy (everything else is truthy):

  • NonePython's null value
  • FalseBoolean false
  • 0, 0.0Zero numbers of any numeric type
  • "", [], {}Empty string, list, dict, set, tuple
Idiomatic Python: if my_list: (truthy if non-empty) is preferred over if len(my_list) > 0:.
02_types.py
03

Control Flow

if/elif/else, for loops, while loops, and Python 3.10's match/case. Python's for loop iterates directly over any collection — no manual index management needed.

if / elif / else for / in while break / continue range() enumerate() match / case ternary

for loops — iterate directly

Python's for loop iterates over any iterable — lists, strings, dicts, files, generators. You almost never need a manual index.

  • range(n)Generates integers 0 to n-1. range(2, 10, 2) → 2,4,6,8.
  • enumeratefor i, val in enumerate(lst): — gives index AND value. Never write range(len(lst)).
  • zip()for a, b in zip(lst1, lst2): — iterate two lists together.
  • for…elseThe else block runs if the loop completed without hitting a break.

Ternary expression

value_if_true if condition else value_if_false

Example: label = "even" if n % 2 == 0 else "odd"

match / case (Python 3.10+)

Structural pattern matching. More powerful than a switch statement — it can match values, types, sequences, and guard conditions.

Common pitfall: elif is one word (not else if). And Python has no do…while — use while True: with a break.
03_control.py
04

Functions

Functions are first-class objects — they can be passed as arguments, returned from other functions, and stored in variables. Python functions have powerful argument handling with defaults, *args, and **kwargs.

def / return default args *args **kwargs lambda closures decorators generators / yield type hints

Argument types

  • positionalStandard args. greet("Alice")
  • keywordNamed at call site. greet(name="Alice") — order doesn't matter.
  • defaultdef f(x, n=10): — n is optional. Defaults evaluated once at definition time.
  • *argsVariadic positional. Collected into a tuple inside the function.
  • **kwargsVariadic keyword. Collected into a dict inside the function.
Default argument gotcha — never do this:
def f(items=[]): # items shared across ALL calls!

Use None and create the mutable default inside:
def f(items=None):
    items = items or []

Generators

A function with yield becomes a generator. It produces values lazily — pausing at each yield and resuming when the caller asks for the next item. Memory-efficient for large sequences.

Decorators

@decorator above a function is shorthand for f = decorator(f). Decorators wrap a function to add behavior (logging, timing, caching) without modifying its code.

04_functions.py
05

Classes & OOP

Python is fully object-oriented. Everything is an object — including integers, functions, and modules. Classes are defined with the class keyword; self is the instance passed as the first argument to every method.

class / self __init__ inheritance super() @property @classmethod @dataclass dunder methods

self is not a keyword

self is just the conventional name for the first parameter of an instance method — Python passes the instance automatically. You could name it anything, but always use self.

Privacy conventions

namePublic — accessible everywhere. _name"Private by convention" — don't access from outside the class. __nameName-mangled to _ClassName__name. Harder to accidentally override.

@dataclass — modern Python

The @dataclass decorator auto-generates __init__, __repr__, and __eq__ from field annotations. Recommended for data-holding classes.

Key dunder methods

MethodCalled when
__init__MyClass() — constructor
__str__print(obj) / str(obj)
__repr__repr(obj) / console display
__len__len(obj)
__eq__obj1 == obj2
__enter__/__exit__with obj:
05_oop.py
06

Collections

Python has four built-in collection types, each optimised for different use cases. Choosing the right one matters for both correctness and performance.

list [] tuple () dict {} set {} slicing unpacking collections module

Choosing the right collection

TypeOrderedMutableUniqueBest for
list []Sequences you add/remove from
tuple ()Fixed records, function returns
dict {}✓*keysKey→value mapping
set {}Membership test, deduplication

* dicts preserve insertion order since Python 3.7

Slicing — works on any sequence

lst[start:stop:step]

  • lst[2:5]Items at index 2, 3, 4 (stop is exclusive)
  • lst[:3]First 3 items
  • lst[-3:]Last 3 items (negative counts from end)
  • lst[::-1]Reverse a sequence
  • lst[::2]Every second item

Tuple unpacking

x, y = (3, 4) — assigns both at once. Works with any iterable. Use *rest to collect remaining items: first, *rest = [1, 2, 3, 4]

06_collections.py
07

Comprehensions

Pythonic one-line syntax for building collections by filtering and transforming iterables. More readable than loops in most cases, and often faster.

list comprehension dict comprehension set comprehension generator expression nested comprehension

The pattern

[expression for item in iterable if condition]

All three parts map directly to what you'd write in a for loop:

  • expressionWhat to do with each item (transform)
  • for item inSource iterable to loop over
  • if conditionOptional filter — only include items where this is truthy

Four types

SyntaxProduces
[x for x in it]list
{k: v for ...}dict
{x for x in it}set (unique, unordered)
(x for x in it)generator (lazy, no memory)
Use a generator expression when you only need to iterate once: sum(x**2 for x in range(1_000_000)) — this never builds the list in memory. Just change [] to ().
Comprehension vs for loop — readability guide

Use a comprehension when the result is a single collection and the logic fits on one readable line.

Use a for loop when you have multiple operations per item, nested logic, or side effects (printing, writing to a file).

Never nest more than two comprehensions — the readability cost outweighs the conciseness.

07_comprehensions.py
08

Exception Handling

Python uses exceptions for error handling. The try/except/else/finally pattern lets you handle errors gracefully without crashing. Always catch the most specific exception type you can.

try / except else / finally raise as e custom exceptions common types

try/except/else/finally

  • tryThe code that might raise an exception.
  • exceptRuns if an exception matches. Can have multiple except clauses.
  • elseRuns only if no exception was raised. Good for code that shouldn't be in try.
  • finallyAlways runs — exception or not. Use for cleanup (closing files, releasing resources).

Common exceptions

ExceptionCause
ValueErrorRight type, wrong value: int("abc")
TypeErrorWrong type: "a" + 1
KeyErrorDict key missing: d["missing"]
IndexErrorList index out of range
FileNotFoundErrorFile or path doesn't exist
AttributeErrorNone.strip()
PermissionErrorNo permission to read/write
ZeroDivisionErrorx / 0
Mac-specific: PermissionError is common when trying to write to /usr/local/ or /System/. Always write files to ~/Documents/ or your project folder.
08_exceptions.py
09

Files & I/O

Reading and writing files on macOS. Always use pathlib.Path for paths (macOS-native). Always use context managers (with open()). Always specify encoding="utf-8".

open() / with read / write pathlib.Path json csv encoding

File modes

ModeMeaning
"r"Read (default). FileNotFoundError if missing.
"w"Write. Creates or overwrites.
"a"Append. Creates if missing, never overwrites.
"x"Exclusive create. FileExistsError if it exists.
"rb"/"wb"Binary mode. For images, PDFs, ZIPs.

pathlib on Mac

Path.home() returns /Users/username on Mac. Use / operator to build paths: Path.home() / "Documents" / "data.json"

Mac Desktop/Documents: On macOS 13+, Desktop and Documents may be in iCloud Drive. If you get PermissionError, check System Settings → Privacy & Security → Files and Folders and grant Terminal access.

Always specify encoding

macOS defaults to UTF-8, but always specify it explicitly for portability: open("f.txt", encoding="utf-8"). This prevents issues when files are shared with Windows users.

09_files.py
10

Modules & Packages

A module is a .py file. A package is a folder with an __init__.py. Virtual environments keep your project's packages isolated from other projects and from the system.

import from … import venv pip __name__ packages requirements.txt

Virtual environments — always use them

A virtual environment creates an isolated Python installation for each project. Packages installed in one environment don't affect others.

Mac venv workflow:
cd ~/PythonProjects/myapp
python -m venv .venv
source .venv/bin/activate
pip install requests

Your prompt changes to (.venv) % when active. To deactivate: deactivate

The script guard

When Python runs a file directly: __name__ == "__main__". When it's imported as a module: __name__ == "modulename". Always guard your entry point:

if __name__ == "__main__":
    main()

VS Code on Mac

After activating your venv, open the project folder: code . in Terminal. Press ShiftP → "Python: Select Interpreter" → choose .venv/bin/python.

10_modules.py
11

Advanced Features

Context managers, async/await, itertools, functools, and the walrus operator. These features appear in real-world Python code — understanding them helps you read other people's code.

context managers async / await itertools functools lru_cache := walrus dataclass

Context managers — with statement

Any object with __enter__ and __exit__ methods can be used with with. The __exit__ is always called — even on exceptions — making cleanup reliable.

Walrus operator := (Python 3.8+)

Assigns and returns a value in a single expression. Useful in while loops and if statements to avoid redundant calls:

while chunk := file.read(8192):

async / await

Cooperative multitasking for I/O-bound code (network requests, file reading). async def defines a coroutine. await suspends it until the awaited operation completes. Run with asyncio.run(main()).

functools.lru_cache

Memoizes a function — caches return values by arguments. @lru_cache(maxsize=128) above a recursive or expensive function can give dramatic speedups.

Python 3.9+ shortcut: Use @cache from functools instead of @lru_cache(maxsize=None) — same behavior, cleaner syntax.
11_advanced.py
12

Standard Library

Python ships with "batteries included" — a massive standard library covering almost every common task. No pip required for these.

datetime os / sys pathlib re collections json / csv subprocess random
datetime
Dates, times, timezones

datetime.now(), strftime(), timedelta. Use zoneinfo (3.9+) for timezone-aware datetimes.

pathlib
Object-oriented paths

Path.home() on Mac returns /Users/you. Use / to join: Path.home() / "Desktop".

os / sys
Operating system interface

os.environ["HOME"], os.getcwd(), sys.argv for command-line args, sys.exit().

subprocess
Run shell commands from Python

subprocess.run(["ls", "-la"]). On Mac this lets you call any Terminal command from a Python script.

re
Regular expressions

re.search(r"\d+", text), re.findall(), re.sub(). Prefix patterns with r"..." to avoid double-escaping.

json
JSON encode / decode

json.dumps(data, indent=2) to serialize. json.loads(text) to parse. json.dump/load for files.

collections
Specialised containers

Counter for frequency counts, defaultdict for auto-creating missing keys, deque for fast queue operations.

random
Randomness (non-cryptographic)

random.choice(lst), random.randint(1,100), random.shuffle(lst). For crypto use secrets module.

argparse
Command-line argument parsing

Build scripts with proper --flag arguments: parser.add_argument("--output"). Runs beautifully in Mac Terminal.

urllib / http
HTTP without pip

urllib.request.urlopen(url) for basic HTTP. For real projects, install requests or httpx via pip.

csv
Spreadsheet data

csv.DictReader(f) reads rows as dicts using the header row. csv.DictWriter writes them. Works great with Numbers exports.

sqlite3
Embedded database

A full SQL database in a single file. No server needed. conn = sqlite3.connect("app.db"). Great for Mac apps storing structured data.

12_stdlib_examples.py
PEP 8 — Python Style Guide (essential rules)
RuleCorrectWrong
Indentation4 spacestabs, 2 spaces, 3 spaces
Function namessnake_casecamelCase
Class namesPascalCasesnake_case
ConstantsUPPER_CASElower_case
Max line length79 characters200-char lines
Blank lines2 between top-level defs0 or 1
ImportsOne per line, at topimport os, sys
Spaces around =x = 5x=5
No spaces in keyword argsf(n=5)f(n = 5)
Auto-format on Mac: Install black with pip install black then run black myfile.py. In VS Code, install the Black formatter extension and press ShiftF to format.
Recommended Mac Python Tools
ToolPurposeInstall
blackAuto-formatter — makes your code PEP 8 compliantpip install black
ruffFast linter — catches errors and style issuespip install ruff
mypyStatic type checker — validates your type hintspip install mypy
pytestTest framework — run with pytest in Terminalpip install pytest
ipythonEnhanced interactive Python REPLpip install ipython
jupyterNotebook interface — great for data explorationpip install jupyter