learn

Syntax cheat sheet

Every line of syntax this roadmap teaches, gathered in one place — 352 of them, in the order you meet them rather than alphabetically. Each one also appears under the concept that explains it; this page is for when you are building something and cannot remember what the thing was called.

352 lines

What Python actually is

python3 --version
Prints the installed version, which proves the command works at all.On Windows the command is usually python or py, not python3.
python3
Opens the interactive prompt, where each line runs the moment you press Enter.
exit()
Leaves the interactive prompt and returns you to the shell.
print("Hello")
Writes text to the terminal. The quotes are part of the syntax, not the message.
python3 hello.py
Runs a file from top to bottom, then exits.
# a note to yourself
A comment. Python ignores everything after the # on that line.
pip --version
Confirms the package installer is present, and says which Python it belongs to.

What a code editor is for

mkdir learn
Creates a folder for your work, from the terminal.
cd learn
Moves the terminal into that folder, so every later command runs there.
code .
Opens the current folder in VS Code. The dot means “here”.
ls
Lists what is in the current folder.Windows Command Prompt uses dir instead; PowerShell accepts ls.

Variables and types

count = 3
Binds the name count to the value 3. No type declaration needed.
name, age = "Ada", 36
Assigns several names at once, left to right.
count += 1
Shorthand for count = count + 1. Also -=, *=, /=.
type(count)
Tells you what kind of value a name currently holds.
total = None
The “nothing yet” value, for a name that exists but has no answer.Test it with `if total is None:`, never == None.
MAX_TRIES = 5
A constant by convention. Capitals tell a reader not to reassign it; Python will not stop you.

Getting information in and out

answer = input("Your name: ")
Prints the prompt, waits, and returns what was typed.
age = int(input("Age: "))
Converts the typed text into a whole number.input ALWAYS returns a string. "3" + 1 is an error; int("3") + 1 is 4.
print(f"{name} is {age}")
An f-string: anything inside the braces is evaluated and inserted.
print(f"{price:.2f}")
Formats a number to two decimal places.
print(a, b, sep=", ")
Prints several values with a separator you choose.
print("loading", end="")
Prints without starting a new line.

Operators — doing things to values

7 / 2
True division. Gives 3.5, a float, even when both sides are whole.
7 // 2
Floor division. Gives 3, discarding the remainder.
7 % 2
Remainder. Gives 1, and n % 2 == 0 is the standard even test.
2 ** 10
Power. Two to the tenth.
a == b
Compares values. Also !=, <, >, <=, >=.One = assigns, two == compares. Mixing them up is the classic first bug.
x > 0 and y > 0
Both must hold. Also or for either, not to invert.
"a" in word
Membership. Works on strings, lists, sets, and dictionary keys.
0 < x < 10
A chained comparison, meaning both at once. It reads exactly like the maths.

Conditionals — making decisions

if x > 0:
Runs the indented block below only when the test is true.
elif x == 0:
Checked only when every test above it failed. Use as many as you like.
else:
Runs when nothing above matched. At most one, and it takes no test.
if items:
Truthiness. An empty list, an empty string, 0 and None are all false.
label = "odd" if n % 2 else "even"
A conditional expression, for when a whole if-block would be four lines of noise.
if value is None:
An identity test, and the correct way to check for None.is asks “the same object?”, == asks “the same value?”. Use is only for None, True and False.

Loops — repeating work

for item in items:
Visits each element in turn. No index arithmetic needed.
for i in range(5):
Counts 0, 1, 2, 3, 4. The end is excluded.
for i in range(2, 10, 2):
Start, stop, step: 2, 4, 6, 8.
for i, item in enumerate(items):
Gives you the position and the value together.
for a, b in zip(xs, ys):
Walks two sequences side by side, stopping at the shorter one.
while not done:
Repeats while a condition holds. Use it when you cannot say in advance how many times.
break
Leaves the loop immediately.
continue
Skips to the next iteration without finishing this one.

Indentation is not decoration

if x: do_something()
Four spaces mark the body. The indentation IS the block — there are no braces.
pass
A block that does nothing, for when the syntax demands a body you have not written yet.
total = (first + second)
Brackets let one expression span lines, and indentation inside them is free.

Functions

def greet(name):
Defines a function. The body is the indented block below.
return value
Hands a result back to the caller and stops the function.A function with no return gives back None.
def greet(name, greeting="Hi"):
A default, used when the caller omits that argument.
greet(name="Ada")
A keyword argument. Clearer than position once there are several.
def total(*numbers):
Collects any number of positional arguments into a tuple.
def config(**options):
Collects any number of keyword arguments into a dictionary.
def add(a: int, b: int) -> int:
Type hints. Python does not enforce them; they are for readers and tools.
"""One line saying what it does."""
A docstring, the first thing in the body. help(add) prints it.

Scope — where a name is visible

count = 0
At module level, outside any function. Readable from inside one.
global count
Declares that assignments in this function change the module-level name.Needed only to ASSIGN. Reading an outer name works without it.
nonlocal total
The same idea, but for the enclosing function rather than the module.
def f(items=None): items = items or []
The safe way to default a mutable argument.def f(items=[]) reuses ONE list across every call — a bug that costs an hour to find.

Lists

items = [1, 2, 3]
A list literal: ordered, changeable, duplicates allowed.
items[0]
The first element. items[-1] is the last.
items[1:3]
A slice — a new list holding elements 1 and 2. The end is excluded.
items.append(4)
Adds one element to the end.
items.extend([5, 6])
Adds every element of another sequence.
items.pop()
Removes and returns the last. items.pop(0) takes the first.pop(0) shifts every remaining element. Use collections.deque if you do it in a loop.
items.remove(2)
Removes the first element equal to 2. Raises ValueError if there is none.
items.sort()
Sorts in place and returns None. sorted(items) returns a new list instead.
items.sort(key=len, reverse=True)
Sorts by a computed value, longest first.
len(items)
How many elements. Works on strings, dictionaries and sets too.
copy = items[:]
A shallow copy.copy = items is the SAME list under a second name — changing one changes both.

Dictionaries

ages = {"ada": 36}
A dictionary literal: keys mapped to values.
ages["ada"]
Looks up a key. Raises KeyError if it is missing.
ages.get("bob", 0)
Looks up a key, returning a fallback instead of raising.
ages["bob"] = 41
Adds or overwrites. There is no separate insert.
"ada" in ages
Tests for a KEY, not a value. Average O(1).
for key, value in ages.items():
Walks pairs. .keys() and .values() give one side each.
ages.setdefault("cy", []).append(1)
Fetches the key, inserting a default first if it is absent. The one-line “group into buckets”.
del ages["bob"]
Removes a key. ages.pop("bob", None) removes it without raising.
ages.update(other)
Merges another dictionary in, overwriting on collision.

Tuples and sets

point = (3, 4)
A tuple: ordered like a list, but immutable.
x, y = point
Unpacking. Works for any sequence of the right length.
first, *rest = items
Takes one element and collects the remainder into a list.
seen = set()
An empty set.{} is an empty DICTIONARY, not a set. This trips up everyone once.
seen = {1, 2, 3}
A set literal: unordered, no duplicates, average O(1) membership.
seen.add(4)
Adds one element. Adding a duplicate does nothing at all.
a & b
Intersection. Also | union, - difference, ^ symmetric difference.
set(items)
Deduplicates any sequence.Order is not preserved. list(dict.fromkeys(items)) dedupes and keeps it.

List comprehensions

[x * 2 for x in items]
Builds a new list by transforming each element.
[x for x in items if x > 0]
Filters. The condition goes at the end.
[f(x) if x else 0 for x in items]
Chooses per element. This if/else goes BEFORE the for; a filtering if goes after.
{k: v for k, v in pairs}
A dictionary comprehension.
{word.lower() for word in words}
A set comprehension, which deduplicates as it builds.
sum(x * x for x in items)
A generator expression. It computes lazily, so nothing large is built in memory.
[c for word in words for c in word]
Flattens. The for clauses read left to right, exactly like nested loops.Past two clauses, write the loop out. Clever is not the goal.

Reading a stack trace

raise ValueError("n must be positive")
Signals a failure yourself, with a message the traceback will show.
import traceback
The module for handling tracebacks as data.
traceback.print_exc()
Prints the current exception and its traceback from inside an except block.
raise ValueError("bad row") from err
Chains a new error onto the original, so the traceback shows both causes.

Handling exceptions

try:
Starts a protected block. The risky work goes here.
except ValueError:
Handles one specific failure. Prefer this to a bare except.
except (KeyError, IndexError) as err:
Catches several kinds and binds the object to a name.
else:
Runs only if nothing was raised, keeping its own errors out of the handler.
finally:
Runs either way. The place to release things.
raise
Re-raises the exception you are handling, unchanged, after logging it.
class ParseError(Exception):
Your own exception type, so callers can catch exactly this failure.
with open(path) as f:
A context manager: cleanup happens even if the block raises.

Reading and writing files

with open("notes.txt") as f:
Opens for reading, and closes automatically at the end of the block.
text = f.read()
Reads the whole file into one string.
for line in f:
Streams one line at a time, so the file's size stops mattering.
open(path, "w")
Opens for writing.w TRUNCATES the file immediately. Use a to append.
f.write("text\n")
Writes a string. Unlike print, it adds no newline for you.
open(path, encoding="utf-8")
States the encoding explicitly, so the file reads the same on every machine.
import json
The standard reader and writer for structured data files.
json.load(f)
Reads JSON from a file into dictionaries and lists. json.dump(obj, f) writes it back.
from pathlib import Path
Paths as objects: Path("data") / "x.txt", .exists(), .read_text().

Debugging

print(f"{value=}")
Prints the expression AND its value — value=3. Made for exactly this.
breakpoint()
Stops execution here and drops you into the debugger. Delete it before committing.
n
In the debugger: run the next line. s steps into a call, c continues, q quits.
p variable
In the debugger: print a value. pp pretty-prints, l lists the source around you.
assert total >= 0, total
Crashes immediately if an assumption is false, showing the offending value.
import sys; sys.exit(1)
Stops the program with a failure code, for when continuing would do damage.

Reproducing a bug before fixing it

def test_empty_input_returns_zero():
A test is a function whose name starts with test_. pytest finds it for you.
assert total([]) == 0
The whole assertion vocabulary you need to start. pytest shows both sides on failure.
pytest
Runs every test it can find under the current folder.
pytest -k empty
Runs only tests whose name contains “empty” — the fast loop while fixing one bug.
pytest -x
Stops at the first failure instead of reporting all of them.
with pytest.raises(ValueError):
Asserts that the block DOES raise. A test that expects a crash.
@pytest.mark.parametrize("n,want", [(0, 1), (5, 120)])
Runs the same test body over several cases, reporting each separately.

Logging you will thank yourself for at 3am

import logging
The standard library's logging system. Prefer it to print for anything long-lived.
logging.basicConfig(level=logging.INFO)
Turns logging on and sets the threshold. Call it once, at program start.
log = logging.getLogger(__name__)
A logger named after the module, so the output says where each line came from.
log.info("loaded %s rows from %s", count, path)
Logs with the values filled in.Pass values as arguments rather than building an f-string; then the formatting is skipped entirely when the level is off.
log.warning("retrying %s", url)
Something odd but survivable. debug < info < warning < error < critical.
log.exception("could not parse %s", path)
Logs at error level AND attaches the traceback. Use it inside except.
logging.basicConfig(filename="app.log")
Sends records to a file instead of the terminal.

Bisecting a failure

git bisect start
Begins a bisect session.
git bisect bad
Marks the current commit as broken.
git bisect good a1b2c3d
Marks a commit you know was fine. Git then checks out the midpoint for you.
git bisect run pytest -k parse
Runs the whole search automatically, using the command's exit code as the answer.
git bisect reset
Ends the session and puts you back where you started.
git log --oneline -20
Finds a commit hash to use as your known-good point.

Modules — splitting code across files

import math
Makes the module available as math.sqrt(9).
from math import sqrt
Pulls one name in directly, so you write sqrt(9).
import numpy as np
Imports under a shorter name.
from .helpers import clean
A relative import, from a module beside this one in the same package.
if __name__ == "__main__":
Runs the block only when the file is executed directly, not when it is imported.Without it, importing your file runs its script code as a side effect.
python3 -m mypackage
Runs a package as a program.

Classes and objects

class Dog:
Defines a new kind of thing. Capitalised by convention.
def __init__(self, name):
The constructor. It runs when you write Dog("Rex").
self.name = name
Stores a value on this particular object.
def bark(self):
A method. self is the first parameter of every one, and Python passes it for you.
rex = Dog("Rex")
Creates an instance. There is no new keyword.
isinstance(rex, Dog)
Asks whether an object is of a given type.
class Puppy(Dog):
Inherits everything from Dog, and may override parts.
super().__init__(name)
Calls the parent's version, so its setup still happens.

Why objects exist at all

from dataclasses import dataclass
Generates __init__, __repr__ and __eq__ from the fields you declare.
@dataclass class Point: x: int y: int
A whole class in four lines, with equality and printing that already work.
@property def area(self):
A computed attribute, read as shape.area with no parentheses.
@staticmethod
A function that lives on the class but needs no instance.
@classmethod def from_row(cls, row):
An alternative constructor, receiving the class instead of an instance.

Making objects printable

def __str__(self):
What print(obj) and str(obj) show. For humans.
def __repr__(self):
What the prompt and containers show. For you, debugging — aim for something unambiguous.
return f"Dog({self.name!r})"
!r inserts the repr, so strings keep their quotes.
def __eq__(self, other):
Defines what == means for your type.
def __len__(self):
Makes len(obj) work. Same idea for __iter__, __contains__ and __getitem__.

Composition — objects holding other objects

self.engine = Engine()
Composition: an object holding another object, and the default choice.
def start(self): return self.engine.start()
Delegation. Forward the call to the part that owns the job.
def __init__(self, store): self.store = store
Dependency injection: the collaborator is passed in, so a test can pass a fake.
class Engine(Protocol):
From typing. Describes what a collaborator must provide, with no inheritance.

A gentle first look at recursion

def countdown(n): if n == 0: return countdown(n - 1)
A function calling itself, with a base case that stops it.
return 1 if n <= 1 else n * factorial(n - 1)
The recursive step. Every call must move toward the base case.
import sys; sys.setrecursionlimit(10000)
Raises the default limit of about a thousand frames.Usually the wrong fix. Deep recursion in Python normally wants a loop and an explicit stack.
from functools import cache
Decorate with @cache and repeated calls with the same arguments are remembered instead of recomputed.

Big-O notation

for item in items:
One pass over the input: the usual O(n) shape.
for left in items: for right in items:
Compares every pair: O(n squared), which becomes expensive quickly.
items.sort()
Sorts a list in O(n log n) time in the usual case.
while low <= high: mid = (low + high) // 2 if items[mid] < target: low = mid + 1 else: high = mid - 1
Halves the remaining search space each turn: O(log n).

Recursion and the call stack

def factorial(n): if n <= 1: return 1 return n * factorial(n - 1)
The recursive shape: stop at a base case, then make one smaller call.
from functools import cache
Imports the decorator that remembers repeated recursive subproblems.
@cache def fib(n): if n < 2: return n return fib(n - 1) + fib(n - 2)
Caches Fibonacci results so each n is calculated once.
stack = [root]
Starts an explicit stack, the loop-friendly replacement for deep recursion.

The small amount of maths you need

import math
Imports the standard library's number helpers.
n % 2 == 0
Tests whether n is even.
math.gcd(a, b)
Finds the greatest common divisor, useful for simplifying fractions and cycles.
math.lcm(a, b)
Finds the least common multiple.
pow(base, exponent, modulus)
Computes a power modulo modulus without constructing the huge full power.

Arrays and dynamic arrays

nums = [10, 20, 30]
Creates an ordered, indexable run of values.
nums[1]
Reads an item by position in O(1) time.
nums.append(40)
Adds an item at the end, the usual cheap array operation.
nums[1:3]
Takes a slice from index 1 up to, but not including, 3.

Linked lists

node.next = Node(value)
Links a new node after the current one.
new.next = head head = new
Inserts a node at the front in O(1) time.
current = head while current is not None: current = current.next
Walks every node from the head to the end.
slow = fast = head
Starts slow and fast pointers, useful for detecting a cycle or finding a middle.

Stacks

stack = []
Creates a stack using a Python list.
stack.append(value)
Pushes value onto the top.
value = stack.pop()
Pops and returns the most recently pushed value.
if stack:
Checks that a stack has something to pop.

Queues, deques and priority queues

from collections import deque
Imports Python's efficient queue type.
queue = deque([start])
Creates a queue with its first item already waiting.
queue.append(item)
Adds item at the back of the queue.
item = queue.popleft()
Takes the oldest item from the front in O(1) time.list.pop(0) shifts every remaining item. Use deque when you remove from the front in a loop.

Hash tables

seen = set()
Creates a hash set for fast membership checks.
counts = {}
Creates a dictionary, Python's hash table.
counts[value] = counts.get(value, 0) + 1
Counts occurrences without a separate missing-key branch.
from collections import defaultdict
Imports a dictionary that creates a default value for new keys.
groups = defaultdict(list)
Creates buckets that begin as empty lists.

Strings

word = "algorithm"
Creates an immutable sequence of characters.
word[::-1]
Returns the characters in reverse order.
word.lower()
Makes a lower-case copy before a case-insensitive comparison.
"".join(chars)
Builds one string from character pieces.Repeated text += piece in a large loop keeps making new strings; collect pieces and join once.
word.isalnum()
Checks that every character is a letter or number.

Choosing what to assert

assert total([]) == 0
States the expected behaviour for an empty input.
assert find([7], 7) == 0
Covers the one-item boundary where loops often go wrong.
assert sorted(values) == [1, 2, 3]
Checks a visible result rather than how the function reached it.
with pytest.raises(ValueError): parse("bad")
Asserts that invalid input fails in the promised way.

Examples versus properties

assert reverse([1, 2, 3]) == [3, 2, 1]
A named example with one known answer.
assert reverse(reverse(items)) == items
A property: reversing twice restores any input.
assert sorted(result) == sorted(items)
Checks that a sort kept every original item.
assert all(result[i] <= result[i + 1] for i in range(len(result) - 1))
Checks the ordering property of every adjacent pair.

Keeping fixed bugs fixed

def test_empty_input_regression():
Names a test after the bug it prevents from returning.
assert parse("") == []
Locks down the smallest input that previously broke.
pytest -k regression
Runs only tests whose names include regression.
pytest -x
Stops at the first failure while you are fixing a bug.

Judging generated code

assert function_name(input_value) == expected
Checks one generated claim against a concrete expected result.
assert function_name([]) == expected_empty
Tests the empty boundary a plausible first draft often misses.
assert function_name(data) == function_name(list(data))
Checks that equal inputs give equal answers without unexpected mutation.
git diff --check
Finds whitespace errors in a generated patch before reviewing its logic.

Debugging as a procedure

assert actual == expected, (actual, expected)
Stops at the first broken assumption and shows both values.
print(f"{index=}, {value=}")
Prints labelled state while tracing a small failing case.
breakpoint()
Pauses at the suspicious line so you can inspect live state.
pytest -k failing_test -x
Runs one failing test and stops immediately, keeping the feedback loop short.

Getting your bearings

rg -n "def target_name" .
Finds a function definition before reading a codebase at random.
rg -n "target_name" .
Finds every call site, test and reference for a name.
git log --oneline -10
Shows the recent changes that explain what the project has been doing.
pytest -q
Establishes whether the current checkout already passes its tests.

Tracing one path end to end

rg -n "/api/orders" app lib
Finds the route or handler that receives one request path.
print(f"{request_id=}, {user_id=}")
Labels one request's values while following its path.
breakpoint()
Pauses at a hand-off to inspect exactly what crosses the boundary.
raise ValueError(f"unexpected state: {state!r}")
Stops a trace at an impossible state with its useful value attached.

Changing unfamiliar code safely

git status --short
Shows local changes before you begin, so you do not mix work together.
git diff -- path/to/file
Reviews only the file you intended to change.
pytest -q
Checks that the existing behaviour still passes after a small edit.
git diff --check
Catches trailing whitespace and conflict-marker mistakes before sharing a diff.

Reading a change, not just a diff

git diff
Shows your unstaged changes line by line.
git diff --stat
Summarises which files changed and by how much before the detail.
git diff --word-diff
Highlights the changed words inside a long line.
git show --stat HEAD
Summarises the latest commit before opening its full patch.
git diff --check
Finds whitespace errors and conflict markers in the diff.

Trees and binary trees

class Node: def __init__(self, value): self.value = value self.left = self.right = None
Defines a minimal binary-tree node.
if node is None: return
The base case for an empty child.
visit(node.value) walk(node.left) walk(node.right)
Preorder traversal: visit a node before its children.
walk(node.left) visit(node.value) walk(node.right)
Inorder traversal, which visits a BST in sorted order.

Binary search trees

if value < node.value: node = node.left else: node = node.right
Chooses the left or right subtree using the BST ordering rule.
while node is not None:
Searches down a tree until it finds a value or reaches an empty child.
if value == node.value: return node
Stops a BST search when the target is found.
node = node.left
Moves toward smaller values in a binary search tree.

Self-balancing trees, and why databases care

height = 1 + max(left_height, right_height)
Computes a node's height from its children.
balance = left_height - right_height
Computes the AVL balance factor for a node.
if abs(balance) > 1: node = rebalance(node)
Repairs an AVL node whose two sides differ too much in height.
return rotate_left(node)
Performs a rotation to shorten a right-heavy subtree.

Heaps

import heapq
Imports Python's min-heap tools.
heap = [3, 1, 4] heapq.heapify(heap)
Turns a list into a min-heap in place.
heapq.heappush(heap, item)
Adds an item while keeping the smallest item at heap[0].
smallest = heapq.heappop(heap)
Removes and returns the smallest item.
heapq.heappush(heap, (-priority, item))
Uses negative priorities when you need a max-heap.Tuples break ties with their next item. Add a counter if equal priorities contain values Python cannot compare.

Tries

node = {}
Uses a dictionary as one trie node, mapping characters to children.
node = node.setdefault(char, {})
Follows a character edge, creating it if it is new.
node["$"] = True
Marks that a complete word ends at this node.
for char in word: if char not in node: return False node = node[char]
Follows a word through a trie and fails as soon as a prefix is absent.

Graphs

graph = {"A": ["B", "C"], "B": []}
Represents a graph as an adjacency list.
graph[a].append(b)
Adds a directed edge from a to b.
graph[b].append(a)
Adds the reverse edge too, for an undirected graph.
for neighbour in graph[node]:
Visits each edge leaving a node.

Union-find

parent = list(range(n))
Starts n separate groups, each item its own parent.
def find(x): if parent[x] != x: parent[x] = find(parent[x]) return parent[x]
Finds a group's root and compresses the path for later calls.
root_a, root_b = find(a), find(b)
Finds the representative of each group before comparing or merging.
parent[root_b] = root_a
Merges two different groups by attaching one root to the other.

Binary search

low, high = 0, len(nums) - 1
Sets inclusive bounds for a sorted list.
mid = (low + high) // 2
Finds the middle index of the remaining range.
if nums[mid] < target: low = mid + 1 else: high = mid - 1
Discards the half that cannot contain the target.
import bisect pos = bisect.bisect_left(nums, target)
Finds where target belongs in a sorted list.
if pos < len(nums) and nums[pos] == target:
Checks that a bisect position really contains the target.bisect returns an insertion point even when the target is absent.

Sorting

nums.sort()
Sorts a list in place, ascending.
ordered = sorted(nums, reverse=True)
Returns a new list in descending order.
people.sort(key=lambda person: person.age)
Sorts objects by a chosen value.
words.sort(key=str.lower)
Sorts text without treating capitals separately.
pairs.sort(key=lambda pair: (pair[1], pair[0]))
Sorts by one field, then breaks ties with another.

Breadth-first and depth-first search

from collections import deque
Imports the queue used by breadth-first search.
queue = deque([start]) seen = {start} while queue: node = queue.popleft() for neighbour in graph[node]: if neighbour not in seen: seen.add(neighbour); queue.append(neighbour)
The BFS shape: visit graph nodes one distance layer at a time.
stack = [start] seen = set() while stack: node = stack.pop() if node not in seen: seen.add(node); stack.extend(graph[node])
An iterative DFS, which goes deep along one path before backtracking.
seen.add(start)
Marks a node when it enters the frontier, preventing duplicate queue work.

Shortest paths

dist = {node: float("inf") for node in graph} dist[start] = 0
Initialises every distance as unknown, except the starting point.
import heapq pq = [(0, start)]
Starts Dijkstra's priority queue with the source at distance zero.
cost, node = heapq.heappop(pq)
Takes the next node with the cheapest known route.
if cost + weight < dist[neighbour]: dist[neighbour] = cost + weight heapq.heappush(pq, (dist[neighbour], neighbour))
Relaxes an edge when it improves a neighbour's best route.
if cost != dist[node]: continue
Skips an old heap entry after a better route was found.Dijkstra is not correct when any edge has a negative weight.

Minimum spanning trees

edges.sort(key=lambda edge: edge[2])
Orders weighted edges from cheapest to most expensive for Kruskal's algorithm.
if find(a) != find(b):
Checks whether an edge would join two separate components.
union(a, b) mst.append((a, b, weight))
Accepts an edge and merges its two components.
if len(mst) == len(vertices) - 1: break
Stops once the spanning tree has enough edges.

Topological sort

from graphlib import TopologicalSorter
Imports the standard-library tool for dependency ordering.
order = list(TopologicalSorter(graph).static_order())
Returns a valid order for a dependency graph.
indegree[child] += 1
Counts one prerequisite edge into child.
if indegree[neighbour] == 0: queue.append(neighbour)
Queues work once every prerequisite has been removed.
if len(order) != len(graph): raise ValueError("cycle")
Detects a cycle when Kahn's algorithm cannot order every node.

Brute force

for left in range(len(nums)): for right in range(left + 1, len(nums)): if nums[left] + nums[right] == target: return left, right
Checks every pair, a clear first solution for two-sum.
from itertools import combinations
Imports a generator for choosing groups without writing nested loops.
for pair in combinations(nums, 2):
Visits every two-item combination.
best = min(candidates, key=score)
Chooses the best answer after trying every candidate.

Divide and conquer

mid = len(items) // 2
Finds a midpoint for splitting a problem in two.
left = solve(items[:mid]) right = solve(items[mid:])
Solves two smaller halves recursively.
return combine(left, right)
Combines the two solved halves into one answer.
if len(items) <= 1: return items
Stops when the problem is already small enough to answer directly.

Greedy algorithms

intervals.sort(key=lambda interval: interval[1])
Orders intervals by earliest finishing time for interval scheduling.
if start >= last_end: chosen.append((start, end)) last_end = end
Takes the next compatible interval after choosing the earliest finish.
for coin in sorted(coins, reverse=True):
Considers the largest available coin first.
take = min(remaining // coin, available)
Takes as much of a locally best choice as the constraints allow.

Backtracking

def search(path): if complete(path): answers.append(path.copy()) return
Ends one branch when it forms a complete answer.
for choice in choices(path): path.append(choice) search(path) path.pop()
The choose, explore, un-choose shape for exhaustive search.
if not valid(path): return
Prunes a branch as soon as it cannot lead to a valid answer.
answers.append(path.copy())
Saves the current answer without sharing the mutable path.Appending path itself saves repeated references to one list, which later pops will empty.

Dynamic programming

from functools import cache
Imports memoisation for a top-down dynamic programme.
@cache def ways(n): if n <= 1: return 1 return ways(n - 1) + ways(n - 2)
Turns repeated recursive subproblems into one cached result each.
dp = [0] * (n + 1)
Allocates a table with one answer slot per subproblem.
for i in range(2, n + 1): dp[i] = dp[i - 1] + dp[i - 2]
Builds answers bottom-up after their dependencies exist.
dp = [[0] * cols for _ in range(rows)]
Creates independent rows for a two-dimensional table.[[0] * cols] * rows repeats the same row object, so one write appears in every row.

Two pointers, sliding windows and prefix sums

left, right = 0, len(nums) - 1
Starts two pointers at opposite ends of a sorted list.
while left < right: total = nums[left] + nums[right] if total < target: left += 1 else: right -= 1
Moves the useful pointer after comparing a pair sum with the target.
left = 0 for right, value in enumerate(nums):
Grows a sliding window one item at a time.
while window_sum > limit: window_sum -= nums[left] left += 1
Shrinks a window until it satisfies its constraint.

Bit manipulation

n & 1
Reads the last bit: 1 for odd n, 0 for even n.
n >> 1
Shifts bits right by one, like floor-dividing a non-negative integer by two.
n | (1 << bit)
Sets a numbered bit to 1.
n & ~(1 << bit)
Clears a numbered bit to 0.
n ^ (1 << bit)
Flips a numbered bit.
n & (n - 1)
Clears the lowest set bit, useful for counting set bits.

Segment trees and Fenwick trees

size = 1 while size < n: size *= 2
Rounds the leaf capacity up to a power of two.
tree = [0] * (2 * size)
Allocates an iterative segment tree with leaves after index size.
tree[size + index] = value
Stores one input value in its leaf position.
tree[index] = tree[2 * index] + tree[2 * index + 1]
Combines two child ranges into their parent range.

String search algorithms

pattern in text
Checks whether a substring occurs anywhere in text.
text.find(pattern)
Returns the first match position, or -1 when there is none.
from collections import Counter
Imports a frequency table for character-count comparisons.
Counter(word) == Counter(candidate)
Tests whether two words are anagrams.
prefix = [0] * len(pattern)
Starts the prefix table used by Knuth-Morris-Pratt matching.

Randomised and approximate algorithms

import random
Imports Python's ordinary pseudo-random tools.
random.shuffle(items)
Randomly rearranges a list in place.
choice = random.choice(items)
Selects one item uniformly from a non-empty sequence.
sample = random.sample(items, k=3)
Selects distinct items without replacement.
from secrets import token_urlsafe token = token_urlsafe(32)
Creates a security-sensitive random token.random is predictable enough for simulations and games, not passwords, reset links or tokens.