Quick Reference · general-purpose programming language · v2

python cheat sheet v2 · single source of truth

Everything in Python is a name bound to an object. Master four mental models — name lookup (LEGB), object mutability, the iteration protocol, and the concurrency map — and the rest of the language is detail, not mystery.

core syntax & types data structures control & functions oop · typing · concurrency gotcha most common

Distilled & cross-checked across: docs.python.org/3 · PEPs 572 · 634 · 695 · 703 · realpython.com · python.org "What's New" 3.10–3.13 · w3schools · geeksforgeeks

Name resolution — where Python looks up a name (LEGB)
Local inside the current function params, loop vars, x = 1 assignment ⇒ local by default Enclosing outer function's scope closures capture this Global top level of the module import, module constants Built-in the builtins module len, range, print, str… not found → not found → not found → nonlocal x global x (forces assignment into module scope) YOUR FUNCTION MODULE & PYTHON ITSELF
The iteration protocol — what every for-loop does under the hood
Iterable list · dict · str · file · range defines __iter__() Iterator stateful · consumed once defines __next__() value loop body runs Stop Iteration loop exits cleanly iter(obj) next(it) repeat until exhausted for x in obj: ≡ it = iter(obj); while True: x = next(it) … except StopIteration: break
Part I · Foundations
01Run & Environmentstart here
02Variables & Assignmentnames → objects
03Numbers & Operatorsarithmetic & logic
04Numeric Precision & Mathfloat · decimal · math
05Strings & Methodsimmutable text
06f-strings & Format Spec{value:fill align width .prec type}
07Truthiness & Nonewhat counts as False
Part II · Data Structures
08Listsordered, mutable · O(1) append
09Tuples & Setsimmutable / unique · O(1) lookup
10Dictionarieskey → value · insertion-ordered
11Slice Notationseq[start:stop:step]
12collectionsspecialized containers
13heapq & bisectpriority & sorted access
Part III · Control Flow & Functions
14Control Flowbranching
15Pattern Matchingmatch / case · 3.10+
16Loopsiteration
17Iterators & Protocoliter / next / StopIteration
18Built-in Functionsalways available
19Functionssignatures
20Closures & Scopeglobal · nonlocal · late binding
21Lambdas & Functionalfunctools · operator
22Comprehensionsbuild collections concisely
23Generatorslazy · one value at a time
24Decoratorswrap behavior
25Context Managerswith · guaranteed cleanup
26itertoolsiterator algebra
27functoolsfunction tools
Part IV · Object-Oriented Python
28Classes & Instancesthe basics
29Magic (Dunder) Methodsoperator overloading
30Inheritance & MROsuper · abc · mixins
31Dataclassesless boilerplate
32Enum · NamedTuple · TypedDictstructured alternatives
Part V · Errors, I/O & Data
33Exceptionsfail gracefully
34File I/O & Pathlibread / write / paths
35JSON & Serializationjson · csv · pickle
36Regex — re modulepattern matching on text
37datetimedates · times · zones
Part VI · Typing, Async & Concurrency
38Type Hintsfor tooling, not runtime
39Async / Awaitcooperative concurrency
40Threads, Processes & the GILparallelism
Part VII · Project, Tooling & Quality
41Modules, Packages & venvorganize & isolate
42CLI, Env & OSscripts that take input
43Loggingprint() for production
44Testingpytest-first
45Debugging & Profilingfind it, then time it
46Common Pitfallshandle with care

Objects, references & evaluation

Same-looking code, different runtime behavior — where most Python bugs actually come from.

aliasing a mutable object

b = a doesn't copy the list — both names point at the same object, so mutating through either one is visible from both.

a b [1, 2, 3, 4] one object · two names · b.append(4) changes both

shallow vs. deep copy

copy() duplicates the outer container only; nested lists stay shared. deepcopy() recursively duplicates everything.

original shallow copy shared inner [ ] deepcopy's own [ ]

eager list vs. lazy generator

A list comprehension computes every value immediately. A generator expression computes one value at a time, only when asked.

[x*x for x …] (x*x for x …) all in memory one at a time

decorator call flow

@decorator replaces the function with a wrapper. The wrapper decides if/when the original actually runs.

caller wrapper() func() ★ return

sync vs. async timeline

Three I/O calls, 1 s each. Sequential code waits 3 s total; with gather/TaskGroup the waits overlap and finish in ~1 s.

sync async 3 s ~1 s — waits overlap

choosing a concurrency model

The decision is about what your task is waiting on: I/O (network, disk) → asyncio or threads; CPU (math, parsing) → processes.

what's slow? waiting on I/O burning CPU asyncio threads processes 1000s of conns

Numeric identities & caveats

The formulae behind Python's number behavior — the four facts that explain most numeric surprises.

the divmod identity

Floor division and modulo always satisfy this equation — and % takes the divisor's sign, unlike C.

a == (a // b) * b + (a % b) -7 // 2 → -4 -7 % 2 → 1 // floors toward −∞; % result has the sign of the divisor

IEEE-754 floats aren't decimal

0.1 has no exact binary representation, so tiny errors accumulate. Compare with a tolerance, never with ==.

0.1 + 0.2 → 0.30000000000000004 math.isclose(a, b) · Decimal("0.1") for money

round() is banker's rounding

Ties round to the nearest even digit (IEEE-754 default) — this halves cumulative bias but surprises spreadsheet users.

0.5 → 0 1.5 → 2 2.5 → 2 3.5 → 4 half-to-even · need half-up? use Decimal.quantize(ROUND_HALF_UP)

ints never overflow

Python integers have arbitrary precision — they grow as needed. Only floats hit representation limits.

2 ** 1000 → exact 302-digit int float: max ≈ 1.8e308, then OverflowError / inf

Worth memorizing

is ≠ ==is checks identity; == checks value — is only for None
mutable defaultsevaluated once at def time — use None as a sentinel
copy ≠ deepcopycopy() is one level deep; nested mutables still shared
list * n[[0]*3]*3 repeats one inner list, not three
global vs nonlocalglobal → module scope; nonlocal → enclosing function
param orderpositional-only / normal *args keyword-only **kwargs
iterators die oncea consumed generator/iterator yields nothing on pass two
set/dict need hashablekeys & members must be immutable-ish (tuple ✓, list ✗)
EAFP over LBYLtry/except beats pre-checking in idiomatic Python
await ≠ callcalling a coroutine does nothing until awaited/scheduled
GIL rule of thumbI/O-bound → asyncio/threads · CPU-bound → processes
case NAME capturesbare names in match bind — dotted names compare
encoding="utf-8"always pass it to open(); platform defaults differ
except Exceptionnever bare except: — it eats KeyboardInterrupt too
sorted() is stableequal keys keep order — chain sorts from minor to major key
f"{x=}"the fastest debug print you'll ever type