if / elif / else
if cond:
...
elif other:
...
else:
...
Run the first block whose condition is true.
score = 72
if score >= 90:
print("A")
elif score >= 70:
print("C")
else:
print("F")
C
Every keyword, operator, built-in function and common method in one place. Each entry gives the syntax, a one-line explanation and an example whose output was produced by actually running it. Search it, link to any entry, or print the one-page version for your desk.
227 entries
The statements every Python program is built from. Learn it in a course
if cond:
...
elif other:
...
else:
...
Run the first block whose condition is true.
score = 72
if score >= 90:
print("A")
elif score >= 70:
print("C")
else:
print("F")
C
for fruit in ["apple", "pear"]:
print(fruit)
apple
pear
n = 3
while n > 0:
print(n)
n -= 1
3
2
1
for n in range(10):
if n % 2:
continue
if n > 6:
break
print(n)
0
2
4
6
for x in items:
...
else:
...
The else block runs only if the loop finished without break.
for n in [3, 5, 7]:
if n % 2 == 0:
print("found even")
break
else:
print("no even numbers")
no even numbers
def area(w, h):
return w * h
print(area(3, 4))
12
square = lambda x: x * x
print(square(7))
49
class Dog:
def __init__(self, name):
self.name = name
print(Dog("Rex").name)
Rex
try:
...
except Error as e:
...
else:
...
finally:
...
Handle errors; else runs if nothing failed, finally always runs.
try:
n = int("42")
except ValueError:
print("not a number")
else:
print("parsed", n)
finally:
print("done")
parsed 42
done
try:
raise ValueError("age must be positive")
except ValueError as e:
print(e)
age must be positive
with open("note.txt", "w") as f:
f.write("hi")
print(f.closed)
True
import module
from module import name as alias
Load a module, or specific names from it.
import math
from statistics import mean as avg
print(math.pi > 3, avg([1, 2, 3]))
True 2
def todo():
pass
print(todo())
None
nums = [1, 2, 3]
del nums[0]
print(nums)
[2, 3]
try:
assert 2 + 2 == 5, "maths is broken"
except AssertionError as e:
print(e)
maths is broken
global name
nonlocal name
Assign to a variable from an outer scope instead of creating a local one.
count = 0
def bump():
global count
count += 1
bump(); bump()
print(count)
2
def countdown(n):
while n:
yield n
n -= 1
print(list(countdown(3)))
[3, 2, 1]
def describe(cmd):
match cmd.split():
case ["go", direction]:
return f"moving {direction}"
case ["quit"]:
return "bye"
case _:
return "unknown"
print(describe("go north"))
print(describe("dance"))
moving north
unknown
age = 20
print("adult" if age >= 18 else "minor")
adult
words = ["hi", "hello", "hey"]
if (n := len(words)) > 2:
print(f"{n} words")
3 words
# comment
"""Docstring."""
# starts a comment; a string as a function's first line documents it.
def greet():
"""Say hello."""
return "hello" # the result
print(greet.__doc__)
Say hello.
Arithmetic, comparison, logic, unpacking and slicing. Learn it in a course
print(7 / 2, 7 // 2, 7 % 2, 2 ** 10)
3.5 3 1 1024
age = 30
print(18 <= age < 65, 3 == 3.0, 'a' < 'b')
True True True
a and b
a or b
not a
Boolean logic that short-circuits and returns one of its operands.
name = ""
print(name or "anonymous")
print(not name, 0 and 5)
anonymous
True 0
print("py" in "python", 4 not in [1, 2, 3], "a" in {"a": 1})
True True True
x = None
print(x is None, [] is [], [] == [])
True False True
total = 10
total += 5
total *= 2
print(total)
30
a, b = iterable
first, *rest = iterable
Assign several names at once; * collects the remainder.
a, b = 1, 2
a, b = b, a
first, *rest = [10, 20, 30]
print(a, b, first, rest)
2 1 10 [20, 30]
[*a, *b]
{**d1, **d2}
f(*args, **kwargs)
Spread a sequence or mapping into a new one, or into a call.
a, b = [1, 2], [3]
print([*a, *b])
print({**{"x": 1}, **{"y": 2}})
print(max(*a, *b))
[1, 2, 3]
{'x': 1, 'y': 2}
3
seq[start:stop:step]
Take part of a sequence; stop is excluded; negatives count from the end.
nums = [0, 1, 2, 3, 4, 5]
print(nums[1:4], nums[:2], nums[-2:], nums[::2], nums[::-1])
[1, 2, 3] [0, 1] [4, 5] [0, 2, 4] [5, 4, 3, 2, 1, 0]
print(6 & 3, 6 | 3, 6 ^ 3, ~6, 1 << 4, 32 >> 2)
2 7 5 -7 16 8
** then * / // % then + -
Higher precedence binds first; use parentheses when in doubt.
print(2 + 3 * 4, (2 + 3) * 4, -2 ** 2)
14 20 -4
Available everywhere, no import needed. Learn it in a course
print(*values, sep=' ', end='\n')
Write values to the output, separated by sep and followed by end.
print("a", "b", "c", sep="-")
print("no newline", end="!")
print()
a-b-c
no newline!
print(len("hello"), len([1, 2]), len({"a": 1}))
5 2 1
print(type(3), type("x"), type([]))
<class 'int'> <class 'str'> <class 'list'>
print(isinstance(3, int), isinstance(3.0, (int, float)), isinstance("3", int))
True True False
int(x, base=10)
float(x)
str(x)
bool(x)
Convert between the basic types.
print(int("42") + 1, int("ff", 16), float("2.5"), str(7) + "!", bool(""), bool("x"))
43 255 2.5 7! False True
list(iterable)
tuple(iterable)
set(iterable)
dict(pairs)
Build a collection from any iterable.
print(list("abc"), tuple([1, 2]), sorted(set([3, 1, 3])), dict([("a", 1)]))
['a', 'b', 'c'] (1, 2) [1, 3] {'a': 1}
print(list(range(5)), list(range(2, 10, 3)), list(range(5, 0, -1)))
[0, 1, 2, 3, 4] [2, 5, 8] [5, 4, 3, 2, 1]
for i, name in enumerate(["Ada", "Bo"], start=1):
print(i, name)
1 Ada
2 Bo
names = ["Ada", "Bo"]
scores = [90, 85]
print(list(zip(names, scores)))
print(dict(zip(names, scores)))
[('Ada', 90), ('Bo', 85)]
{'Ada': 90, 'Bo': 85}
print(sum([1, 2, 3]), sum(x * x for x in range(4)))
6 14
min(iterable, key=None, default=...)
max(a, b, ...)
Smallest or largest item, optionally compared by a key.
words = ["pear", "fig", "banana"]
print(min(3, 1, 2), max(words), max(words, key=len))
print(max([], default=0))
1 pear banana
0
words = ["pear", "Fig", "apple"]
print(sorted(words))
print(sorted(words, key=str.lower))
print(sorted([3, 1, 2], reverse=True))
['Fig', 'apple', 'pear']
['apple', 'Fig', 'pear']
[3, 2, 1]
print(list(reversed([1, 2, 3])), "".join(reversed("abc")))
[3, 2, 1] cba
abs(x)
round(x, ndigits)
pow(base, exp, mod)
divmod(a, b)
Number helpers. round() uses banker's rounding at exact halves.
print(abs(-5), round(3.14159, 2), round(2.5), pow(2, 10), divmod(17, 5))
5 3.14 2 1024 (3, 2)
nums = [2, 4, 7]
print(any(n % 2 for n in nums), all(n > 0 for n in nums))
True True
map(func, iterable)
filter(func, iterable)
Apply a function to every item, or keep items where it is true.
print(list(map(str.upper, ["a", "b"])))
print(list(filter(lambda n: n > 2, [1, 2, 3, 4])))
['A', 'B']
[3, 4]
input(prompt='')
Read a line typed by the user. It does not work in the browser editors here; use a variable instead.
name = "Ada" # in a terminal: name = input("Name? ")
print(f"Hello, {name}")
Hello, Ada
with open("demo.txt", "w") as f:
f.write("line 1\nline 2")
with open("demo.txt") as f:
print(f.read().splitlines())
['line 1', 'line 2']
print(ord("A"), chr(97), chr(ord("a") + 1))
65 a b
print(bin(10), hex(255), oct(8))
0b1010 0xff 0o10
iter(iterable)
next(iterator, default)
Get an iterator and pull items from it one at a time.
it = iter([1, 2])
print(next(it), next(it), next(it, "done"))
1 2 done
getattr(obj, name, default)
setattr(obj, name, value)
hasattr(obj, name)
Read, set or check an attribute by its name as a string.
class Box: pass
b = Box()
setattr(b, "size", 3)
print(getattr(b, "size"), hasattr(b, "colour"), getattr(b, "colour", "none"))
3 False none
print(callable(len), callable(42))
True False
print(repr("hi"), str("hi"), repr([1, "a"]))
'hi' hi [1, 'a']
a = [1]
b = a
print(id(a) == id(b), hash(42))
True 42
class P:
def __init__(self):
self.x, self.y = 1, 2
print(vars(P()))
print([n for n in dir("") if n.startswith("is")][:3])
{'x': 1, 'y': 2}
['isalnum', 'isalpha', 'isascii']
print(len.__doc__.splitlines()[0])
Return the number of items in a container.
Everything you can call on a str. Learn it in a course
s.upper()
s.lower()
s.title()
s.capitalize()
Change letter case. Strings never change in place; each returns a new string.
s = "hello wORLD"
print(s.upper(), s.lower(), s.title(), s.capitalize(), sep=" | ")
HELLO WORLD | hello world | Hello World | Hello world
s.casefold()
s.swapcase()
Aggressive lowercasing for comparisons, and inverting case.
print("Straße".casefold() == "STRASSE".casefold(), "PyThOn".swapcase())
True pYtHoN
s.strip(chars=None)
Remove whitespace (or given characters) from the ends.
print(repr(" hi ".strip()), "xxhixx".strip("x"), repr(" hi ".rstrip()))
'hi' hi ' hi'
s.split(sep=None, maxsplit=-1)
Break a string into a list. With no sep, splits on any whitespace.
print("a b c".split())
print("2026-10-03".split("-"))
print("a,b,c".split(",", 1))
['a', 'b', 'c']
['2026', '10', '03']
['a', 'b,c']
print("one\ntwo\n".splitlines())
['one', 'two']
print(", ".join(["a", "b", "c"]))
print("-".join(str(n) for n in [1, 2, 3]))
a, b, c
1-2-3
print("a-b-c".replace("-", "+"), "a-b-c".replace("-", "", 1))
a+b+c ab-c
s.find(sub)
s.index(sub)
Position of a substring. find gives -1 if missing; index raises.
print("banana".find("an"), "banana".rfind("an"), "banana".find("x"))
1 3 -1
print("banana".count("a"))
3
s.startswith(prefix)
s.endswith(suffix)
Check the start or end; accepts a tuple of options.
f = "report.pdf"
print(f.endswith((".pdf", ".docx")), f.startswith("rep"))
True True
s.removeprefix(prefix)
s.removesuffix(suffix)
Drop an exact prefix or suffix if present (3.9+).
print("v1.2".removeprefix("v"), "data.csv".removesuffix(".csv"))
1.2 data
s.isdigit()
s.isalpha()
s.isalnum()
s.isspace()
Test what kind of characters a string contains.
print("123".isdigit(), "abc".isalpha(), "a1".isalnum(), " ".isspace(), "".isdigit())
True True True True False
print("ABC".isupper(), "abc1".islower())
True True
s.center(width, fill)
s.ljust(width)
s.rjust(width)
s.zfill(width)
Pad a string to a width.
print("[" + "hi".center(6, "*") + "]", "[" + "hi".ljust(4) + "]", "42".zfill(5))
[**hi**] [hi ] 00042
print("key=value=x".partition("="))
print("a.b.c".rpartition("."))
('key', '=', 'value=x')
('a.b', '.', 'c')
b = "café".encode("utf-8")
print(b, b.decode("utf-8"))
b'caf\xc3\xa9' café
s = "python"
print(s[0], s[-1], s[1:4], s[::-1])
p n yth nohtyp
print("ab" + "cd", "-" * 10)
abcd ----------
"\n" "\t" "\\" r"C:\path"
Backslash codes for special characters; r'' turns them off.
print("a\tb")
print(r"C:\new\table")
a b
C:\new\table
text = """first
second"""
print(text.splitlines())
['first', 'second']
s.translate(str.maketrans(from, to, delete))
Replace or delete many characters in one pass.
table = str.maketrans("ae", "43", "!")
print("hello there!".translate(table))
h3llo th3r3
The format mini-language inside {}. Learn it in a course
name, n = "Ada", 3
print(f"{name} has {n * 2} points")
Ada has 6 points
price = 9.5
print(f"{price=}", f"{price * 2 = }")
price=9.5 price * 2 = 19.0
word = "hi"
print(f"{word} vs {word!r}")
hi vs 'hi'
print(f"{3.14159:.2f}", f"{2:.3f}")
3.14 2.000
print(f"{1234567:,}", f"{1234567.891:,.2f}", f"{1234567:_}")
1,234,567 1,234,567.89 1_234_567
print(f"{0.4567:.1%}", f"{1/3:.0%}")
45.7% 33%
print(f"[{'ab':<6}]", f"[{'ab':>6}]", f"[{'ab':^6}]", f"[{'ab':*^6}]")
[ab ] [ ab] [ ab ] [**ab**]
print(f"{42:05}", f"{3.14159:08.3f}")
00042 0003.142
print(f"{5:+}", f"{-5:+}")
+5 -5
f"{n:b}" f"{n:o}" f"{n:x}" f"{n:#x}"
Binary, octal and hex; # adds the 0b/0o/0x prefix.
print(f"{10:b}", f"{8:o}", f"{255:x}", f"{255:#X}")
1010 10 ff 0XFF
print(f"{123456789:.2e}", f"{0.000123:.1e}")
1.23e+08 1.2e-04
from datetime import date
d = date(2026, 3, 9)
print(f"{d:%d %B %Y}", f"{d:%a %d/%m}")
09 March 2026 Mon 09/03
width, prec = 10, 3
print(f"[{3.14159:{width}.{prec}f}]")
[ 3.142]
x = 5
print(f"{{x}} is {x}")
{x} is 5
"{} {name}".format(a, name=b)
The pre-f-string method, still used for templates stored as data.
template = "Hi {name}, you owe {amount:.2f}"
print(template.format(name="Bo", amount=12.5))
Hi Bo, you owe 12.50
print("%s is %d years old" % ("Ada", 36))
Ada is 36 years old
Ordered, changeable sequences. Learn it in a course
nums = [1, 2]
nums.append(3)
print(nums)
[1, 2, 3]
nums = [1]
nums.extend([2, 3])
print(nums)
[1, 2, 3]
letters = ["a", "c"]
letters.insert(1, "b")
print(letters)
['a', 'b', 'c']
pets = ["cat", "dog", "cat"]
pets.remove("cat")
print(pets)
['dog', 'cat']
stack = [1, 2, 3]
top = stack.pop()
first = stack.pop(0)
print(top, first, stack)
3 1 [2]
nums = [1, 2]
nums.clear()
print(nums)
[]
lst.index(value)
lst.count(value)
Position of the first match, or how many times it appears.
votes = ["y", "n", "y"]
print(votes.index("n"), votes.count("y"))
1 2
lst.sort(key=None, reverse=False)
Sort in place and return None. Use sorted() for a new list.
people = [("Bo", 31), ("Ada", 36)]
people.sort(key=lambda p: p[1], reverse=True)
print(people)
[('Ada', 36), ('Bo', 31)]
nums = [1, 2, 3]
nums.reverse()
print(nums)
[3, 2, 1]
a = [1, 2]
b = a.copy()
b.append(3)
print(a, b)
[1, 2] [1, 2, 3]
[expr for x in iterable if cond]
Build a list in one expression, optionally filtered.
print([n * n for n in range(6) if n % 2 == 0])
[0, 4, 16]
print([f"{r}{c}" for r in "AB" for c in "12"])
['A1', 'A2', 'B1', 'B2']
nums = [0, 1, 2, 3, 4]
nums[1:3] = [9]
print(nums)
[0, 9, 3, 4]
grid = [[0] * cols for _ in range(rows)]
Lists of lists. Build rows with a comprehension so they are separate objects.
grid = [[0] * 3 for _ in range(2)]
grid[0][1] = 5
print(grid)
[[0, 5, 0], [0, 0, 0]]
lst.append() + lst.pop()
collections.deque
Lists are fast stacks; use deque for queues.
from collections import deque
q = deque([1, 2])
q.append(3)
print(q.popleft(), list(q))
1 [2, 3]
Key-value lookup tables. Learn it in a course
ages = {"Ada": 36, "Bo": 31}
print(ages["Ada"])
ages["Cy"] = 28
print(ages)
36
{'Ada': 36, 'Bo': 31, 'Cy': 28}
stock = {"apple": 3}
print(stock.get("apple"), stock.get("pear"), stock.get("pear", 0))
3 None 0
d.keys()
d.values()
d.items()
Views of the keys, values or (key, value) pairs.
prices = {"tea": 2, "cake": 4}
for item, price in prices.items():
print(item, price)
print(list(prices), sum(prices.values()))
tea 2
cake 4
['tea', 'cake'] 6
conf = {"debug": False, "port": 80}
conf.update({"debug": True})
print(conf)
{'debug': True, 'port': 80}
base = {"a": 1, "b": 2}
print(base | {"b": 9, "c": 3})
{'a': 1, 'b': 9, 'c': 3}
d.pop(key, default)
d.popitem()
Remove a key and return its value; popitem removes the last added.
d = {"a": 1, "b": 2}
print(d.pop("a"), d.pop("z", None), d.popitem(), d)
1 None ('b', 2) {}
d.setdefault(key, default)
Return the value, inserting the default first if the key is missing.
groups = {}
groups.setdefault("fruit", []).append("apple")
groups.setdefault("fruit", []).append("pear")
print(groups)
{'fruit': ['apple', 'pear']}
d = {"a": 1}
print("a" in d, 1 in d)
del d["a"]
print(d)
True False
{}
words = ["fig", "apple"]
print({w: len(w) for w in words})
{'fig': 3, 'apple': 5}
print(dict.fromkeys(["a", "b"], 0))
{'a': 0, 'b': 0}
sorted(d.items(), key=lambda kv: kv[1])
Dicts keep insertion order; sort their items to reorder.
scores = {"Ada": 90, "Bo": 72, "Cy": 85}
print(sorted(scores.items(), key=lambda kv: kv[1], reverse=True))
print(max(scores, key=scores.get))
[('Ada', 90), ('Cy', 85), ('Bo', 72)]
Ada
counts = {}
for ch in "banana":
counts[ch] = counts.get(ch, 0) + 1
print(counts)
{'b': 1, 'a': 3, 'n': 2}
user = {"name": "Ada", "address": {"city": "London"}}
print(user["address"]["city"])
print(user.get("phone", {}).get("mobile", "none"))
London
none
a = {"x": 1}
b = a.copy()
b["x"] = 2
print(a, b)
{'x': 1} {'x': 2}
Unique collections and fixed records. Learn it in a course
{1, 2, 3}
set(iterable)
Unordered, unique items. {} alone is an empty dict, so use set().
print(set([3, 1, 3, 2]), set(), type({}))
{1, 2, 3} set() <class 'dict'>
s = {1}
s.add(2)
s.update([3, 4, 1])
print(s)
{1, 2, 3, 4}
s.remove(item)
s.discard(item)
Delete an item; remove raises if missing, discard does not.
s = {1, 2}
s.discard(9)
s.remove(1)
print(s)
{2}
a, b = {1, 2, 3}, {3, 4}
print(a | b, a & b)
{1, 2, 3, 4} {3}
a, b = {1, 2, 3}, {3, 4}
print(a - b, a ^ b)
{1, 2} {1, 2, 4}
print({1, 2} <= {1, 2, 3}, {1, 2, 3} >= {4})
True False
words = ["Hi", "hi", "HEY"]
print(sorted({w.lower() for w in words}))
['hey', 'hi']
fs = frozenset([1, 2])
print({fs: 'pair'}[frozenset([2, 1])])
pair
print(list(dict.fromkeys(["b", "a", "b", "c", "a"])))
['b', 'a', 'c']
t = (1, 2)
t = 1,
t = (1,)
Fixed-size, immutable sequences. A single item needs a trailing comma.
point = (3, 4)
x, y = point
print(x, y, type((1)), type((1,)))
3 4 <class 'int'> <class 'tuple'>
t = (1, 2, 2, 3)
print(t.count(2), t.index(3))
2 3
from collections import namedtuple
Point = namedtuple("Point", "x y")
p = Point(3, 4)
print(p.x, p[1], p)
3 4 Point(x=3, y=4)
Parameters, return values, closures and decorators. Learn it in a course
def f(a, b=10):
Parameters with a fallback value. Never use a mutable default like [].
def greet(name, punct="!"):
return f"Hi {name}{punct}"
print(greet("Ada"), greet("Bo", "?"))
Hi Ada! Hi Bo?
def box(w, h):
return f"{w}x{h}"
print(box(h=2, w=5))
5x2
def total(*nums):
return sum(nums)
print(total(1, 2, 3))
6
def tag(**attrs):
return " ".join(f'{k}="{v}"' for k, v in attrs.items())
print(tag(id="main", lang="en"))
id="main" lang="en"
def f(pos, /, normal, *, kw):
Parameters before / must be positional; after * must be named.
def connect(host, /, port=80, *, secure=False):
return f"{host}:{port} secure={secure}"
print(connect("example.com", secure=True))
example.com:80 secure=True
def min_max(nums):
return min(nums), max(nums)
lo, hi = min_max([4, 1, 9])
print(lo, hi)
1 9
def label(qty: int, unit: str = "item") -> str:
return f"{qty} {unit}s"
print(label(3), label.__annotations__["return"])
3 items <class 'str'>
def outer():
def inner(): ...
return inner
An inner function remembers the variables around it.
def multiplier(n):
def times(x):
return x * n
return times
triple = multiplier(3)
print(triple(5))
15
def shout(fn):
def wrapper(*args):
return fn(*args).upper() + "!"
return wrapper
@shout
def hello(name):
return f"hello {name}"
print(hello("ada"))
HELLO ADA!
def f(n):
if base: return ...
return f(smaller)
A function that calls itself on a smaller input until a base case.
def factorial(n):
return 1 if n <= 1 else n * factorial(n - 1)
print(factorial(5))
120
(expr for x in iterable)
Like a list comprehension but lazy, so it uses almost no memory.
print(sum(n * n for n in range(1_000)))
332833500
f.__name__
funcs = [f, g]
Store functions in variables, lists and dicts, and pass them around.
ops = {"add": lambda a, b: a + b, "mul": lambda a, b: a * b}
print(ops["mul"](3, 4), len.__name__)
12 len
Objects, inheritance, properties and dataclasses. Learn it in a course
class C:
def __init__(self, x):
self.x = x
The initialiser sets up each new object; self is that object.
class Account:
def __init__(self, owner, balance=0):
self.owner = owner
self.balance = balance
acct = Account("Ada", 100)
print(acct.owner, acct.balance)
Ada 100
class Counter:
def __init__(self):
self.n = 0
def tick(self):
self.n += 1
return self.n
c = Counter()
c.tick()
print(c.tick())
2
class Dog:
species = "canine"
def __init__(self, name):
self.name = name
print(Dog("Rex").species, Dog.species)
canine canine
class Child(Parent):
def __init__(self):
super().__init__()
A subclass reuses and extends its parent.
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
return "..."
class Cat(Animal):
def speak(self):
return f"{self.name} says meow"
print(Cat("Tom").speak(), isinstance(Cat("Tom"), Animal))
Tom says meow True
@property
def name(self): ...
A method you read like an attribute, often computed or validated.
class Circle:
def __init__(self, r):
self.r = r
@property
def area(self):
return round(3.14159 * self.r ** 2, 1)
print(Circle(2).area)
12.6
@classmethod
def f(cls, ...):
@staticmethod
def g(...):
classmethod receives the class (good for alternative constructors); staticmethod receives nothing.
class Temp:
def __init__(self, c):
self.c = c
@classmethod
def from_f(cls, f):
return cls(round((f - 32) / 1.8, 1))
@staticmethod
def is_freezing(c):
return c <= 0
print(Temp.from_f(212).c, Temp.is_freezing(-3))
100.0 True
@dataclass
class C:
field: type = default
Generates __init__, __repr__ and __eq__ from annotated fields.
from dataclasses import dataclass, field
@dataclass
class Item:
name: str
price: float
tags: list = field(default_factory=list)
print(Item("pen", 1.5))
print(Item("pen", 1.5) == Item("pen", 1.5))
Item(name='pen', price=1.5, tags=[])
True
from enum import Enum
class Status(Enum):
ACTIVE = "active"
BANNED = "banned"
print(Status.ACTIVE, Status("banned").name, [s.value for s in Status])
Status.ACTIVE BANNED ['active', 'banned']
self._internal
self.__mangled
A leading _ means internal; __ triggers name mangling.
class Safe:
def __init__(self):
self._hint = "internal"
self.__code = 1234
s = Safe()
print(s._hint, hasattr(s, "__code"), s._Safe__code)
internal False 1234
class Base(ABC):
@abstractmethod
def f(self): ...
Force subclasses to implement certain methods.
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self): ...
class Square(Shape):
def __init__(self, s):
self.s = s
def area(self):
return self.s ** 2
print(Square(3).area())
try:
Shape()
except TypeError:
print("cannot instantiate an abstract class")
9
cannot instantiate an abstract class
Hooks that let your objects work with built-in syntax. Learn it in a course
def __repr__(self): ...
def __str__(self): ...
repr is for developers (and debuggers); str is for print().
class Money:
def __init__(self, amount):
self.amount = amount
def __repr__(self):
return f"Money({self.amount})"
def __str__(self):
return f"£{self.amount:.2f}"
m = Money(5)
print(m, repr(m), [m])
£5.00 Money(5) [Money(5)]
def __eq__(self, other): ...
def __lt__(self, other): ...
Define == and < so objects compare and sort by value.
class Version:
def __init__(self, major, minor):
self.v = (major, minor)
def __eq__(self, o):
return self.v == o.v
def __lt__(self, o):
return self.v < o.v
print(Version(1, 2) < Version(1, 10), Version(2, 0) == Version(2, 0))
print([v.v for v in sorted([Version(2, 0), Version(1, 5)])])
True True
[(1, 5), (2, 0)]
def __len__(self): ...
def __getitem__(self, i): ...
Support len(obj) and obj[i] (which also makes it iterable).
class Deck:
def __init__(self):
self.cards = ["A", "K", "Q"]
def __len__(self):
return len(self.cards)
def __getitem__(self, i):
return self.cards[i]
d = Deck()
print(len(d), d[0], list(d))
3 A ['A', 'K', 'Q']
class Range:
def __init__(self, lo, hi):
self.lo, self.hi = lo, hi
def __contains__(self, x):
return self.lo <= x <= self.hi
print(5 in Range(1, 10), 50 in Range(1, 10))
True False
def __iter__(self): ...
def __next__(self): ...
Make an object iterable; raise StopIteration to finish.
class Countdown:
def __init__(self, n):
self.n = n
def __iter__(self):
return self
def __next__(self):
if self.n == 0:
raise StopIteration
self.n -= 1
return self.n + 1
print(list(Countdown(3)))
[3, 2, 1]
def __add__(self, other): ...
Define +, -, * and friends (__sub__, __mul__, __truediv__…).
class Vec:
def __init__(self, x, y):
self.x, self.y = x, y
def __add__(self, o):
return Vec(self.x + o.x, self.y + o.y)
def __repr__(self):
return f"Vec({self.x}, {self.y})"
print(Vec(1, 2) + Vec(3, 4))
Vec(4, 6)
class Adder:
def __init__(self, n):
self.n = n
def __call__(self, x):
return x + self.n
add5 = Adder(5)
print(add5(10))
15
def __enter__(self): ...
def __exit__(self, *exc): ...
Make an object usable in a with block.
class Timer:
def __enter__(self):
print("start")
return self
def __exit__(self, *exc):
print("stop")
with Timer():
print("working")
start
working
stop
class Cart:
def __init__(self, items):
self.items = items
def __bool__(self):
return bool(self.items)
print("has items" if Cart([1]) else "empty", bool(Cart([])))
has items False
def __hash__(self): ...
Needed to put custom objects in sets or use them as dict keys alongside __eq__.
class Tag:
def __init__(self, name):
self.name = name
def __eq__(self, o):
return self.name == o.name
def __hash__(self):
return hash(self.name)
print(len({Tag('a'), Tag('a'), Tag('b')}))
2
What each common error means and how to handle it. Learn it in a course
raised for the right type but a bad value
For example, converting text that is not a number.
try:
int("abc")
except ValueError as e:
print("ValueError:", e)
ValueError: invalid literal for int() with base 10: 'abc'
try:
"age: " + 30
except TypeError as e:
print("TypeError:", e)
TypeError: can only concatenate str (not "int") to str
try:
{"a": 1}["b"]
except KeyError as e:
print("KeyError:", e)
KeyError: 'b'
try:
[1, 2, 3][3]
except IndexError as e:
print("IndexError:", e)
IndexError: list index out of range
try:
10 / 0
except ZeroDivisionError as e:
print("ZeroDivisionError:", e)
ZeroDivisionError: division by zero
try:
(42).upper()
except AttributeError as e:
print("AttributeError:", e)
AttributeError: 'int' object has no attribute 'upper'
raised for a name that was never defined
Usually a typo or using a variable before assigning it.
try:
print(totl)
except NameError as e:
print("NameError:", e)
NameError: name 'totl' is not defined
try:
open("missing.txt")
except FileNotFoundError as e:
print("FileNotFoundError:", e.strerror)
FileNotFoundError: No such file or directory
raised when an import cannot be found
The package is not installed, or the name is misspelt.
try:
import not_a_real_module
except ModuleNotFoundError as e:
print("ModuleNotFoundError:", e)
ModuleNotFoundError: No module named 'not_a_real_module'
it = iter([])
try:
next(it)
except StopIteration:
print("StopIteration: nothing left")
StopIteration: nothing left
raised when recursion goes too deep
A recursive function without a reachable base case.
def forever(n):
return forever(n + 1)
try:
forever(0)
except RecursionError:
print("RecursionError: maximum recursion depth exceeded")
RecursionError: maximum recursion depth exceeded
for raw in ["5", "x", None]:
try:
print(int(raw) * 2)
except (TypeError, ValueError) as e:
print("skipped", type(e).__name__)
10
skipped ValueError
skipped TypeError
class MyError(Exception): ...
Name your own error types so callers can catch them precisely.
class InsufficientFunds(Exception):
pass
try:
raise InsufficientFunds("balance too low")
except InsufficientFunds as e:
print(type(e).__name__, "-", e)
InsufficientFunds - balance too low
raise NewError(...) from original
Re-raise as a clearer error while keeping the original cause.
try:
try:
int("x")
except ValueError as e:
raise RuntimeError("bad config") from e
except RuntimeError as e:
print(e, "| caused by", type(e.__cause__).__name__)
bad config | caused by ValueError
BaseException > Exception > ArithmeticError > ZeroDivisionError
Catching a parent class catches all of its subclasses.
print(issubclass(ZeroDivisionError, ArithmeticError), issubclass(KeyError, LookupError))
True True
Loop helpers and functional tools. Learn it in a course
from itertools import chain
print(list(chain([1, 2], (3,), range(4, 6))))
[1, 2, 3, 4, 5]
product(*iterables, repeat=1)
Every combination of one item from each input (nested loops).
from itertools import product
print(list(product("ab", [1, 2])))
[('a', 1), ('a', 2), ('b', 1), ('b', 2)]
from itertools import permutations
print(["".join(p) for p in permutations("abc", 2)])
['ab', 'ac', 'ba', 'bc', 'ca', 'cb']
combinations(iterable, r)
Every selection of r items where order does not matter.
from itertools import combinations
print(list(combinations([1, 2, 3], 2)))
[(1, 2), (1, 3), (2, 3)]
groupby(sorted_iterable, key)
Group consecutive items with the same key; sort first.
from itertools import groupby
words = sorted(["apple", "avocado", "banana", "blueberry", "cherry"])
for letter, group in groupby(words, key=lambda w: w[0]):
print(letter, list(group))
a ['apple', 'avocado']
b ['banana', 'blueberry']
c ['cherry']
islice(iterable, stop)
count(start, step)
Slice any iterator, or count forever.
from itertools import islice, count
print(list(islice(count(10, 5), 4)))
[10, 15, 20, 25]
accumulate(iterable, func=operator.add)
Running totals (or running anything).
from itertools import accumulate
print(list(accumulate([1, 2, 3, 4])), list(accumulate([3, 1, 4], max)))
[1, 3, 6, 10] [3, 3, 4]
from itertools import pairwise
print([b - a for a, b in pairwise([1, 4, 9, 16])])
[3, 5, 7]
from functools import reduce
print(reduce(lambda a, b: a * b, range(1, 6)))
120
from functools import partial
binary = partial(int, base=2)
print(binary("1010"))
10
@lru_cache(maxsize=128)
@cache
Remember results so repeated calls are instant.
from functools import cache
@cache
def fib(n):
return n if n < 2 else fib(n - 1) + fib(n - 2)
print(fib(80))
23416728348467685
from operator import itemgetter
rows = [("Bo", 31), ("Ada", 36)]
print(sorted(rows, key=itemgetter(1)))
[('Bo', 31), ('Ada', 36)]
Reading, writing and working with paths. Learn it in a course
with open("poem.txt", "w") as f:
f.write("roses\nviolets\n")
with open("poem.txt") as f:
print(repr(f.read()))
'roses\nviolets\n'
with open("poem.txt", "w") as f:
f.write("roses\nviolets\n")
with open("poem.txt") as f:
for n, line in enumerate(f, 1):
print(n, line.strip())
1 roses
2 violets
with open("log.txt", "w") as f:
f.write("first\n")
with open("log.txt", "a") as f:
f.write("second\n")
with open("log.txt") as f:
print(f.read().splitlines())
['first', 'second']
from pathlib import Path
p = Path("data") / "reports" / "q1.csv"
print(p, p.name, p.stem, p.suffix, p.parent)
data/reports/q1.csv q1.csv q1 .csv data/reports
Path(p).read_text()
Path(p).write_text(s)
One-line file reads and writes.
from pathlib import Path
Path("hello.txt").write_text("hi there")
print(Path("hello.txt").read_text(), Path("hello.txt").exists())
hi there True
from pathlib import Path
for name in ["a.txt", "b.txt", "c.csv"]:
Path(name).write_text("")
print(sorted(p.name for p in Path(".").glob("*.txt")))
['a.txt', 'b.txt']
csv.reader / csv.DictReader / csv.writer
Read and write comma-separated data safely, quotes and all.
import csv, io
data = io.StringIO("name,score\nAda,90\nBo,72\n")
for row in csv.DictReader(data):
print(row["name"], int(row["score"]))
Ada 90
Bo 72
import json
with open("save.json", "w") as f:
json.dump({"level": 3, "items": ["key"]}, f)
with open("save.json") as f:
print(json.load(f))
{'level': 3, 'items': ['key']}
import os
print(os.path.join("a", "b.txt"), os.path.splitext("photo.jpg"), os.path.basename("/x/y/z.py"))
a/b.txt ('photo', '.jpg') z.py
The modules worth knowing, one import away. Learn it in a course
import math
print(math.sqrt(16), math.floor(2.7), math.ceil(2.1), round(math.pi, 4))
print(math.gcd(12, 18), math.isclose(0.1 + 0.2, 0.3))
4.0 2 3 3.1416
6 True
import random
random.seed(42)
print(random.randint(1, 6), random.choice(["a", "b", "c"]))
items = [1, 2, 3, 4]
random.shuffle(items)
print(items, round(random.random(), 3))
6 a
[4, 2, 3, 1] 0.245
import statistics as st
data = [2, 4, 4, 5, 7, 9]
print(st.mean(data), st.median(data), st.mode(data), round(st.stdev(data), 2))
5.166666666666667 4.5 4 2.48
from datetime import date, datetime, timedelta
Create, compare and do arithmetic on dates.
from datetime import date, timedelta
d = date(2026, 1, 31)
print(d + timedelta(days=1), (date(2026, 12, 25) - d).days, d.weekday())
2026-02-01 328 5
datetime.strptime(text, fmt)
dt.strftime(fmt)
Turn text into a datetime and back. %Y year, %m month, %d day, %H:%M time.
from datetime import datetime
dt = datetime.strptime("2026-03-09 14:30", "%Y-%m-%d %H:%M")
print(dt.strftime("%A %d %B, %I:%M %p"))
print(dt.isoformat())
Monday 09 March, 02:30 PM
2026-03-09T14:30:00
import json
text = json.dumps({"name": "Ada", "tags": ["x"], "ok": True})
print(text)
print(json.loads(text)["tags"], json.dumps({"b": 1, "a": 2}, sort_keys=True, indent=None))
{"name": "Ada", "tags": ["x"], "ok": true}
['x'] {"a": 2, "b": 1}
re.search(pattern, text)
m.group()
Find the first match of a regular expression.
import re
m = re.search(r"(\d{4})-(\d{2})", "Due 2026-10, ok")
print(m.group(), m.group(1), m.span())
2026-10 2026 (4, 11)
re.findall(p, s)
re.sub(p, repl, s)
re.split(p, s)
All matches, find and replace, or split on a pattern.
import re
text = "Call 555-1234 or 555-9876"
print(re.findall(r"\d{3}-\d{4}", text))
print(re.sub(r"\d", "#", "pin 4821"))
print(re.split(r"[,;]\s*", "a, b;c"))
['555-1234', '555-9876']
pin ####
['a', 'b', 'c']
from collections import Counter
c = Counter("mississippi")
print(c.most_common(2), c["s"], c["z"])
[('i', 4), ('s', 4)] 4 0
from collections import defaultdict
by_letter = defaultdict(list)
for w in ["ant", "bee", "ape"]:
by_letter[w[0]].append(w)
print(dict(by_letter))
{'a': ['ant', 'ape'], 'b': ['bee']}
deque(iterable, maxlen=None)
Fast appends and pops at both ends; maxlen keeps the last N.
from collections import deque
recent = deque(maxlen=3)
for n in range(5):
recent.append(n)
print(list(recent))
[2, 3, 4]
import heapq
tasks = []
for p in [5, 1, 3]:
heapq.heappush(tasks, p)
print(heapq.heappop(tasks), heapq.nlargest(2, [4, 9, 1, 7]))
1 [9, 7]
import bisect
grades = [60, 70, 80, 90]
print(bisect.bisect(grades, 85), 'FDCBA'[bisect.bisect(grades, 85)])
nums = [1, 3, 5]
bisect.insort(nums, 4)
print(nums)
3 B
[1, 3, 4, 5]
from decimal import Decimal
from fractions import Fraction
print(0.1 + 0.2, Decimal("0.1") + Decimal("0.2"), Fraction(1, 3) + Fraction(1, 6))
0.30000000000000004 0.3 1/2
import copy
a = [[1, 2], [3]]
b = copy.deepcopy(a)
b[0].append(99)
print(a, b)
[[1, 2], [3]] [[1, 2, 99], [3]]
import string
print(string.ascii_lowercase[:5], string.digits, len(string.punctuation))
abcde 0123456789 32
textwrap.wrap(text, width)
textwrap.shorten(text, width)
Wrap or truncate text neatly at word boundaries.
import textwrap
text = "Python is a language that reads almost like English."
print(textwrap.wrap(text, 20))
print(textwrap.shorten(text, 30))
['Python is a language', 'that reads almost', 'like English.']
Python is a language [...]
import itertools, functools
See the Iteration section above for the most useful functions.
import itertools, functools
print(len(list(itertools.permutations(range(4)))), functools.reduce(max, [3, 9, 2]))
24 9
import sys
print(sys.version_info.major, sys.getrecursionlimit() > 100)
3 True
from urllib.parse import urlencode, urlparse
print(urlencode({"q": "python tips", "page": 2}))
u = urlparse("https://api.site.com/users?id=7")
print(u.netloc, u.path, u.query)
q=python+tips&page=2
api.site.com /users id=7
uuid.uuid4()
secrets.token_hex(n)
Unique IDs and cryptographically secure random tokens.
import uuid, secrets
print(len(str(uuid.uuid4())), len(secrets.token_hex(8)))
36 16
import time
start = time.perf_counter()
total = sum(range(100_000))
print(total, time.perf_counter() - start >= 0)
4999950000 True
Nothing matches that search. Try a shorter word, such as “sort” or “json”.
Start free. No install, no card, no passive video marathon.