1. Getting Started on Mac
macOS includes Python 3.9 for system use. Never use it. Install Python 3.14 yourself.
Open Terminal
Press ⌘ Space → type "Terminal" → Enter. For a better experience, install iTerm2.
Install Python Properly
# Check system Python (ignore this)
python3 --version
# => Python 3.9.6
# Option A: Homebrew (recommended)
brew install python
python3 --version
# => Python 3.14.0
# Option B: python.org Universal2 installer
# Downloads to /Library/Frameworks/Python.framework
Always use
python3 and pip3, not python. Apple reserves python for Python 2.Create Your First Project
mkdir ~/Projects/hello-mac && cd $_
python3 -m venv .venv
source .venv/bin/activate # (zsh/fish/bash)
# Now 'python' points to 3.14 inside the venv
python -m pip install --upgrade pip
python --version
deactivate # exit venv
VS Code Setup (2026)
- Install VS Code → Extensions: "Python" (Microsoft) + "Pylance"
- Open your project folder
- ⌘⇧P → "Python: Select Interpreter" → pick
./.venv/bin/python - New integrated terminal auto-activates venv
2. Core Syntax Rules
Indentation is law
Use 4 spaces. No tabs, no braces.
def can_vote(age):
if age >= 18:
return True
else:
return False # aligned with 'if'
Comments & Docstrings
# Single line comment
def fetch():
"""Triple-quoted docstring - describes the function."""
pass
Variables & Naming
snake_casefor variables/functionsPascalCasefor classesUPPER_SNAKEfor constants- Case-sensitive:
name≠Name
Dynamic Typing
x = 10 # int
x = "now a string" # same name, new type - allowed
Print and Input
print("Hello Mac")
name = input("Your name? ") # always returns str
F-strings (3.6+) & T-strings (3.14 NEW)
name = "Ada"
year = 2026
print(f"{name} runs Python {year}")
print(f"{year = }") # debug: year = 2026
# Python 3.14 Template Strings - for safe queries
user_id = 42
query = t"SELECT * FROM users WHERE id = {user_id}"
# Unlike f-strings, 'query' is a Template object.
# Database drivers can handle it safely, preventing SQL injection.
# Use for HTML, SQL, shell commands.
3. Data Types
| Type | Example | Mutable? | Notes |
|---|---|---|---|
int | 42, -7 | No | Arbitrary precision |
float | 3.14, 1e-3 | No | IEEE-754 double |
bool | True, False | No | Subclass of int |
str | "Mac", 'hi' | No | Unicode |
NoneType | None | - | Absence of value |
list | [1, 2, 3] | Yes | Ordered collection |
tuple | (1, 2) | No | Immutable list |
dict | {"a":1} | Yes | Key-value map (3.7+ ordered) |
set | {1, 2, 3} | Yes | Unique items, unordered |
frozenset | frozenset([1,2]) | No | Immutable set |
# Type checking
type([1,2]) # <class 'list'>
isinstance(x, str) # True/False
Preview 3.15:
frozendict is coming for immutable dictionaries. For now use from types import MappingProxyType.4. Operators
| Category | Operators | Example |
|---|---|---|
| Arithmetic | + - * / // % ** | 7 // 2 == 3, 2**3 == 8 |
| Comparison | == != < > <= >= | 3 <= 5 |
| Logical | and or not | True and not False |
| Membership | in, not in | "a" in "Mac" |
| Identity | is, is not | x is None (prefer over ==) |
| Assignment | = += := | if n := len(data): (walrus) |
5. Control Flow
# if / elif / else
score = 85
if score >= 90:
grade = "A"
elif score >= 80:
grade = "B"
else:
grade = "C"
# for loop
for app in ["Safari", "Terminal", "VS Code"]:
print(app)
# while with else
n = 3
while n > 0:
print(n)
n -= 1
else:
print("liftoff")
# break / continue
for i in range(10):
if i == 5: continue
if i == 8: break
match-case (Python 3.10+)
match status_code:
case 200 | 201:
print("OK")
case 404:
print("Not found")
case 500 | 502 | 503:
print("Server error")
case _:
print("Unknown")
Comprehensions
squares = [x*x for x in range(5)] # [0,1,4,9,16]
evens = {x for x in range(10) if x % 2 == 0} # set
mapping = {x: chr(65+x) for x in range(3)} # {0:'A',1:'B',2:'C'}
6. Functions & Arguments — The Full Picture
def func_name(parameters) -> return_type:
"""Docstring"""
return value
Positional & Keyword
def add(a, b):
return a + b
add(2, 3) # positional
add(b=3, a=2) # keyword
Default Values
def greet(name, greeting="Hello"):
return f"{greeting}, {name}"
Never use mutable defaults:
def f(x=[]) — use None.*args — Variable Positional
def total(*numbers):
return sum(numbers)
total(1, 2, 3, 4) # 10
**kwargs — Variable Keyword
def config(**options):
print(options)
config(theme="dark", debug=True)
# {'theme': 'dark', 'debug': True}
Keyword-Only Arguments (after *)
def connect(host, *, port=443, timeout=10):
...
connect("apple.com", port=8443) # OK
# connect("apple.com", 8443) # TypeError
Positional-Only (before /) Python 3.8+
def divide(a, b, /, c):
return a / b + c
divide(10, 2, c=5) # a,b must be positional
Complete Signature
def ultimate(pos1, pos2, /, standard, *args, kw_only, **kwargs):
"""Order matters:
1. positional-only
2. standard
3. *args
4. keyword-only
5. **kwargs
"""
Type Hints & Lambdas
def parse(s: str) -> int | None:
return int(s) if s.isdigit() else None
square = lambda x: x * x
# same as def square(x): return x*x
7. Modules & Packages
# Standard library
import os
import sys
from pathlib import Path
from datetime import datetime as dt
# Third-party (after pip install)
import requests
# Never do this:
# from module import *
Installing Packages
# Inside activated venv
pip3 install requests httpx rich
# Pin versions
pip freeze > requirements.txt
# Reinstall elsewhere
pip install -r requirements.txt
On Mac 2026, use
pipx install black ruff for CLI tools to keep them isolated.8. Virtual Environments on Mac
Isolates dependencies per project. macOS Terminal uses zsh by default.
python3 -m venv .venv
source .venv/bin/activate
which python # .../Projects/.../.venv/bin/python
# VS Code detects .venv automatically
# To leave:
deactivate
Add to .zshrc for convenience:
alias venv='python3 -m venv .venv && source .venv/bin/activate'
9. Object-Oriented Python
class MacApp:
platform = "macOS" # class attribute
def __init__(self, name: str, version: float):
self.name = name # instance attribute
self.version = version
def launch(self):
return f"Launching {self.name} {self.version}"
@property
def bundle_id(self):
return f"com.example.{self.name.lower()}"
# Inheritance
class ProApp(MacApp):
def __init__(self, name, version, pro_features):
super().__init__(name, version)
self.pro_features = pro_features
Dataclasses (less boilerplate)
from dataclasses import dataclass
@dataclass
class Window:
title: str
width: int = 800
height: int = 600
visible: bool = True
win = Window("Finder")
10. Error Handling
try:
data = Path("config.json").read_text()
config = json.loads(data)
except FileNotFoundError:
print("Config missing - using defaults")
config = {}
except json.JSONDecodeError as e:
print(f"Invalid JSON: {e}")
raise # re-raise
else:
print("Config loaded successfully")
finally:
print("Cleanup complete")
Raise your own:
if age < 0:
raise ValueError("age cannot be negative")
11. Files & Paths — The Mac Way
Use pathlib, not string concatenation. macOS paths use /.
from pathlib import Path
home = Path.home() # /Users/you
docs = home / "Documents"
project = docs / "Python" / "demo.txt"
# Create directory
project.parent.mkdir(parents=True, exist_ok=True)
# Write
project.write_text("Hello from Mac\n", encoding="utf-8")
# Read safely with context manager
with open(project, "r", encoding="utf-8") as f:
for line in f:
print(line.strip())
# Common operations
list(docs.glob("*.pdf")) # find PDFs
project.exists()
project.unlink() # delete
12. Command-Line Arguments
Basic: sys.argv
import sys
# python3 script.py input.txt -v
print(sys.argv)
# ['script.py', 'input.txt', '-v']
filename = sys.argv[1] if len(sys.argv) > 1 else "default.txt"
Professional: argparse
import argparse
parser = argparse.ArgumentParser(
prog="imgtool",
description="Resize images on macOS"
)
parser.add_argument("input", help="Input image path")
parser.add_argument("-o", "--output", default="out.jpg")
parser.add_argument("-w", "--width", type=int, default=800)
parser.add_argument("-v", "--verbose", action="store_true")
args = parser.parse_args()
print(f"Resizing {args.input} to {args.width}px")
if args.verbose:
print("Verbose mode on")
Run: python3 imgtool.py photo.png -w 1200 -v
13. Standard Library Highlights
| Module | Mac-Relevant Use |
|---|---|
os | os.uname(), os.getenv("HOME") |
sys | sys.platform == 'darwin', argv |
pathlib | All file paths — POSIX paths |
subprocess | Run shell commands: subprocess.run(["open", "."]) |
datetime | Timestamps, timezone handling |
json | Configuration files, APIs |
venv | Create virtual environments |
shutil | Copy, move files like Finder |
argparse | CLI tools |
14. Mac Workflow Tips
ShebangMake scripts executable:
#!/usr/bin/env python3 at top, then chmod +x script.py → ./script.pyOpen in Finder
import subprocess; subprocess.run(["open", "."])Homebrew PythonLives at
/opt/homebrew/bin/python3 (Apple Silicon). Add to PATH automatically.VS Code 2026Use Ruff for instant formatting, Pylance for types, Jupyter notebooks native on Apple Silicon.
CertificatesAfter python.org install, run "Install Certificates.command" in Applications/Python 3.14
pipx & uv
brew install pipx uv — pipx for tools, uv for ultra-fast installs.# Example executable script ~/bin/backup
#!/usr/bin/env python3
from pathlib import Path
import shutil
src = Path.home() / "Documents"
dst = Path("/Volumes/Backup")
shutil.copytree(src, dst / "Documents", dirs_exist_ok=True)
print("Backup complete")
15. Quick Reference Table
| Task | Syntax |
|---|---|
| Create venv | python3 -m venv .venv |
| Activate | source .venv/bin/activate |
| Install package | pip install requests |
| Function | def f(a, b=2, *args, **kw): |
| List comp | [x for x in items if cond] |
| Dict get | d.get('key', default) |
| Path join | Path.home() / "file.txt" |
| F-string | f"{value:.2f}" |
| T-string (3.14) | t"query {x}" |
| Exception | try: ... except E as e: |
| Context manager | with open(f) as fh: |
16. Next Steps Checklist
- Install Python 3.14 via Homebrew and create a test venv
- Configure VS Code to use your venv interpreter
- Write a CLI tool using
argparsewith positional and keyword-only args - Practice pathlib: list all Downloads > 10MB
- Build a small class with dataclass and type hints
- Convert an f-string SQL query to a safe t-string
- Set up Ruff formatting on save in VS Code
- Publish your first package to TestPyPI using
uv build
Pro tip for Mac users: Python feels native when you treat Terminal as your IDE companion. Learn
zsh shortcuts, use pbcopy/pbpaste with subprocess, and automate Finder tasks with Python instead of AppleScript.