The Python syntax you actually reach for daily, organized so you stop scrolling through Stack Overflow. Covers core constructs through modern 3.13+ additions. Each entry has copy-pasteable code and the kind of tips that save you a debugging session.
| Name | Syntax | Description |
|---|---|---|
| List Comprehension | [expr for x in iterable if cond] | Build a list in one expression. Add if-clause to filter, nest for-clauses to flatten. |
| Dict Comprehension | {k: v for k, v in iterable} | Same idea as list comps, but produces a dict. Handy for inverting or filtering mappings. |
| F-Strings | f"{expr}" / f"{val:.2f}" / f"{x=}" | Inline expressions in strings. Supports format specs and = for debug printing. |
| Walrus Operator | if (n := len(items)) > 10: | Assigns and returns in one shot. Avoids redundant calls in conditions and comprehensions. |
| match/case | match value: case pattern: ... | Structural pattern matching (3.10+). Destructures sequences, mappings, and class attributes. |
| Lambda | lambda args: expression | Anonymous single-expression function. Use for short callbacks, not complex logic. |
| *args / **kwargs | def f(*args, **kwargs): | Variadic positional and keyword arguments. args is a tuple, kwargs is a dict. |
| Unpacking | first, *rest = iterable | Destructure sequences. The starred target collects leftover items into a list. |
| Decorators | @decorator\ndef func(): ... | Wrap a function or class. Decorator receives the target and returns a replacement. |
| Generators | def gen(): yield value | Lazy iterator. Yields values one at a time instead of building a full list in memory. |
| Context Managers | with open(path) as f: | Guarantees cleanup via __enter__/__exit__. Use contextlib for lightweight custom managers. |
| Type Hints | def f(x: int) -> str: | Static annotations. No runtime enforcement, but mypy/pyright catch bugs before you ship. |
| @dataclass | @dataclass\nclass Point: x: float; y: float | Auto-generates __init__, __repr__, __eq__. Add frozen=True for immutability. |
| __slots__ | __slots__ = ('x', 'y') | Restricts instance attributes. Saves memory and prevents typo-based attribute creation. |
| ExceptionGroup | except* TypeError as eg: | Catch multiple concurrent exceptions (3.11+). Each except* handles a subset of the group. |
[expr for x in iterable if condition]List comps replace map/filter for most cases. Generator expressions (round parens) are lazy and use constant memory. Use set or dict comps when you need those types directly.
Tips
d.get(key, default) / d | other / d.setdefault(k, v)Dicts are the backbone of Python data handling. The | merge operator (3.9+) replaced {**a, **b}. defaultdict and Counter from collections handle 90% of grouping and counting tasks.
Tips
a, *rest, z = iterable / {**d1, **d2}Unpacking eliminates index-based access and makes code self-documenting. Starred expressions handle variable-length sequences. Double-star unpacking merges dicts (though | is preferred in 3.9+).
Tips
match subject:\n case pattern [if guard]: ...Added in 3.10. Goes far beyond a switch statement: it destructures sequences, mappings, and objects. Guards (if-clauses) add runtime conditions to patterns. The _ wildcard matches anything.
Tips
(name := expression)The walrus operator assigns a value inside an expression, so you can test and capture in one step. Most useful in while-loops, if-conditions, and comprehension filters where you would otherwise need a throwaway variable or redundant call.
Tips
for x in seq:\n ...\nelse:\n # ran if no breakThe else clause on a loop runs only if the loop completed without hitting a break. It is a clean way to handle the "searched but did not find" pattern without extra boolean flags.
Tips
def f(pos, /, normal, *, kw_only, **kwargs):Python gives precise control over how arguments are passed. Positional-only (/) prevents callers from using keyword syntax, which lets you rename parameters later without breaking the API. Keyword-only (*) forces clarity at the call site.
Tips
@decorator\ndef func(): ...Decorators are just higher-order functions. Always use @functools.wraps to preserve the original function's name, docstring, and signature. Decorators with arguments need an extra nesting level.
Tips
def gen(): yield value / yield from iterableGenerators produce values lazily: they only compute the next item when asked. This makes them ideal for large datasets, infinite sequences, and pipeline-style data processing. yield from delegates iteration to another generator or iterable.
Tips
lambda args: expressionLambdas are anonymous single-expression functions. They shine as sort keys, callback arguments, and simple transforms. For anything more than one expression, use a named function.
Tips
@dataclass(frozen=False, slots=False, kw_only=False)Dataclasses auto-generate __init__, __repr__, __eq__, and optionally __hash__. frozen=True gives you immutability. slots=True (3.10+) reduces memory and prevents accidental attribute creation. kw_only=True forces callers to be explicit.
Tips
__slots__ = ('attr1', 'attr2')Slots replace the per-instance __dict__ with a fixed set of attribute descriptors. This saves ~40-60 bytes per instance and speeds up attribute access. In modern Python, @dataclass(slots=True) is the easiest way to enable this.
Tips
with resource as var: / @contextmanagerContext managers guarantee cleanup via the with statement. Use @contextmanager from contextlib instead of writing __enter__/__exit__ by hand. The parenthesized form (3.10+) handles multiple managers cleanly.
Tips
try: ... except Type as e: ... else: ... finally: ...The else clause runs only if try succeeded, keeping the 'happy path' out of the try block. finally always runs regardless. Use 'from' for explicit exception chaining so the traceback shows the causal relationship.
Tips
raise ExceptionGroup(msg, [e1, e2]) / except* Type:Exception groups let you raise and handle multiple exceptions simultaneously. The except* syntax matches subsets of the group by type. Essential for concurrent code where multiple tasks can fail at once.
Tips
x: int | str / list[int] / dict[str, Any]Python's type system has matured rapidly. The X | Y union syntax (3.10+) replaced typing.Union. Built-in generics (3.9+) eliminated imports for list, dict, tuple, and set. The type statement (3.12+) replaced TypeAlias.
Tips
with (\n cm1() as a,\n cm2() as b,\n):The parenthesized with statement (3.10+) makes multiple context managers readable without backslash continuation. Supports trailing commas for easy git diffs when adding or removing managers.
Tips
f"{data["key"]}" / f"{obj!r:>20}"F-strings got major quality-of-life upgrades in 3.12: you can nest the same quote type inside expressions and break expressions across multiple lines. The = specifier (3.8+) is still the fastest debug print trick around.
Tips
type Alias = ... / def f[T](x: T) -> T:The type statement (3.12+) declares type aliases without importing TypeAlias. The bracket syntax [T] on functions and classes replaces explicit TypeVar declarations. Both reduce boilerplate and improve readability.
Tips
Combines dataclasses for typed records, a context manager for file handling, list comprehensions for parsing, and generator expressions for aggregation. This is the kind of pipeline you write every week in data-heavy Python.
A production-grade retry decorator with exponential backoff. Uses modern generic syntax [T], functools.wraps for introspection, and parameterized exception types so you only retry on recoverable failures.
Uses match/case to validate and destructure a TOML config in one step. The pattern enforces required keys and types at parse time. Combined with frozen dataclasses for an immutable config object.
Mutable default arguments are shared across calls: def append_to(item, target=[]) reuses the same list object every time
Use None as the default and create a new object inside the function: def append_to(item, target=None): target = target if target is not None else []. Default argument values are evaluated once at function definition time, not at each call.
Late binding closures in loops: lambdas and inner functions capture the variable, not its current value, so [lambda: i for i in range(3)] all return 2
Bind the value with a default argument: [lambda i=i: i for i in range(3)]. The default argument is evaluated at definition time, freezing the current value of i into each lambda.
is vs ==: 'is' checks identity (same object in memory), '==' checks equality. Small int caching (-5 to 256) makes 'is' seem to work for ints, but it breaks for larger values
Always use == for value comparison. Use 'is' only for singletons: None, True, False. Write 'if x is None', never 'if x == None'.
Modifying a list while iterating over it causes skipped elements or IndexError: for item in my_list: if bad(item): my_list.remove(item)
Iterate over a copy (for item in my_list[:]:) or, better, use a list comprehension to build a new list: my_list = [item for item in my_list if not bad(item)]. The comprehension approach is both safer and more Pythonic.
Integer division with / returns a float, even for exact results: 10 / 2 returns 5.0, not 5. This can cause subtle type bugs in dict keys and equality checks.
Use // for integer division when you want an int result: 10 // 2 returns 5. Be aware that // with negative numbers rounds toward negative infinity: -7 // 2 is -4, not -3.
Go beyond the cheatsheet with hands-on lessons and challenges.