Python cheatsheet
The syntax and standard library I reach for every week
A short reference for everyday Python 3. It covers what I look up most often, with the smallest example that shows the idea.
Basics
x = 10 # int
pi = 3.14 # float
name = "Aymen" # str
ok = True # bool
nothing = None # absence of a value
a, b = 1, 2 # unpacking
a, b = b, a # swap
first, *rest = [1, 2, 3, 4] # first=1, rest=[2, 3, 4]
Useful built-ins: len, range, enumerate, zip, sorted, reversed, sum, min, max, any, all, abs, round.
for i, value in enumerate(["a", "b", "c"], start=1):
print(i, value)
for left, right in zip([1, 2, 3], ["x", "y", "z"]):
print(left, right)
print(any(n > 2 for n in [1, 2, 3])) # True
print(all(n > 0 for n in [1, 2, 3])) # True
Truthiness
Empty containers, 0, 0.0, "" and None are falsy. Everything else is truthy.
if not items: # empty list, dict, set or string
print("nothing here")
value = user_input or "default" # first truthy operand
Operators
| Operator | Meaning | Example |
|---|---|---|
// |
floor division | 7 // 2 gives 3 |
% |
modulo | 7 % 2 gives 1 |
** |
power | 2 ** 10 gives 1024 |
is |
identity | x is None |
in |
membership | "a" in "cat" |
:= |
assignment expression | if (n := len(xs)) > 3: |
Strings
s = "Hello, world"
s.lower(); s.upper(); s.title()
s.strip() # trim whitespace on both sides
s.split(", ") # ['Hello', 'world']
", ".join(["a", "b"]) # 'a, b'
s.replace("world", "you")
s.startswith("Hello")
s.find("world") # index, or -1
s[0]; s[-1]; s[0:5]; s[::-1]
f-strings
name, score = "Aymen", 0.8734
print(f"{name} scored {score:.1%}") # Aymen scored 87.3%
print(f"{1234567:,}") # 1,234,567
print(f"{name!r:>12}") # repr, right-aligned in 12 chars
print(f"{score=}") # score=0.8734
Collections
Lists
xs = [3, 1, 2]
xs.append(4)
xs.extend([5, 6])
xs.insert(0, 9)
xs.pop() # remove and return the last item
xs.remove(1) # remove the first match
xs.sort() # in place
sorted(xs, key=lambda n: -n) # new list
xs[1:3]; xs[::-1]; xs.copy()
Tuples
Immutable and hashable, so they can be dictionary keys.
point = (3, 4)
x, y = point
Dictionaries
user = {"name": "Aymen", "role": "lead"}
user["team"] = "data"
user.get("age") # None instead of KeyError
user.get("age", 0) # with a default
user.setdefault("tags", [])
user.update({"role": "lead dev"})
for key, value in user.items():
print(key, value)
merged = {**user, "city": "Paris"} # copy with an override
combined = user | {"city": "Paris"} # Python 3.9+
Sets
a, b = {1, 2, 3}, {3, 4}
a | b # union
a & b # intersection
a - b # difference
a ^ b # symmetric difference
set(xs) # deduplicate, order is not kept
Comprehensions
squares = [n * n for n in range(10)]
evens = [n for n in range(10) if n % 2 == 0]
lookup = {word: len(word) for word in ["a", "bb", "ccc"]}
unique = {n % 3 for n in range(10)}
total = sum(n * n for n in range(10)) # generator, no list is built
flat = [item for row in matrix for item in row]
Functions
def greet(name: str, *, loud: bool = False) -> str:
message = f"Hello, {name}"
return message.upper() if loud else message
greet("Aymen", loud=True)
*argscollects extra positional arguments into a tuple.**kwargscollects extra keyword arguments into a dict.- Parameters after a bare
*are keyword-only. - Never use a mutable default value such as
def f(xs=[]). UseNoneand create the list inside.
def add_item(item, items=None):
items = [] if items is None else items
items.append(item)
return items
Lambdas, decorators and closures
people.sort(key=lambda p: p["age"])
import functools, time
def timed(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
start = time.perf_counter()
try:
return func(*args, **kwargs)
finally:
print(f"{func.__name__} took {time.perf_counter() - start:.3f}s")
return wrapper
@timed
def work():
...
Generators
def read_chunks(items, size):
for i in range(0, len(items), size):
yield items[i : i + size]
list(read_chunks([1, 2, 3, 4, 5], 2)) # [[1, 2], [3, 4], [5]]
Classes
from dataclasses import dataclass, field
@dataclass(frozen=True)
class Project:
name: str
year: int
tags: list[str] = field(default_factory=list)
@property
def label(self) -> str:
return f"{self.name} ({self.year})"
p = Project("Gtag", 2024)
print(p.label)
A plain class, for comparison:
class Counter:
def __init__(self, start: int = 0):
self.value = start
def increment(self) -> int:
self.value += 1
return self.value
def __repr__(self) -> str:
return f"Counter({self.value})"
Files and paths
from pathlib import Path
path = Path("data") / "notes.txt"
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text("hello\n", encoding="utf-8")
text = path.read_text(encoding="utf-8")
for file in Path("data").glob("*.csv"):
print(file.name, file.stat().st_size)
with open(path, encoding="utf-8") as handle:
for line in handle:
print(line.rstrip())
JSON and CSV
import csv, json
data = json.loads('{"a": 1}')
Path("out.json").write_text(json.dumps(data, indent=2), encoding="utf-8")
with open("rows.csv", newline="", encoding="utf-8") as handle:
for row in csv.DictReader(handle):
print(row["name"])
Errors
try:
value = int(raw)
except ValueError as error:
print(f"not a number: {error}")
except (KeyError, IndexError):
print("missing")
else:
print("parsed", value)
finally:
print("always runs")
raise ValueError("something is wrong")
Define your own exception when callers need to catch it specifically:
class ConfigError(Exception):
pass
Standard library worth knowing
from collections import Counter, defaultdict, deque
from itertools import chain, groupby, islice, product
from datetime import datetime, timedelta, timezone
from functools import lru_cache, partial
Counter("banana").most_common(2) # [('a', 3), ('n', 2)]
groups = defaultdict(list)
for word in ["apple", "avocado", "banana"]:
groups[word[0]].append(word)
now = datetime.now(timezone.utc)
tomorrow = now + timedelta(days=1)
print(now.isoformat())
@lru_cache(maxsize=None)
def fib(n: int) -> int:
return n if n < 2 else fib(n - 1) + fib(n - 2)
Type hints
from typing import Literal, Protocol
def mean(values: list[float]) -> float:
return sum(values) / len(values)
def find(user_id: int) -> dict[str, str] | None:
...
Mode = Literal["read", "write"]
class Closeable(Protocol):
def close(self) -> None: ...
Hints are not enforced at runtime. Run a checker such as mypy or pyright to use them.
Async basics
import asyncio
async def fetch(n: int) -> int:
await asyncio.sleep(0.1)
return n * 2
async def main():
results = await asyncio.gather(fetch(1), fetch(2), fetch(3))
print(results) # [2, 4, 6]
asyncio.run(main())
Environments and tooling
python -m venv .venv
source .venv/bin/activate
python -m pip install requests
python -m pip freeze > requirements.txt
python -m pytest -q
python -m http.server 8000
Gotchas
==compares values,iscompares identity. Useisonly forNone,TrueandFalse.- A default mutable argument is shared between calls.
- Copying a list with
b = amakes a second name for the same list. Usea.copy()ora[:], andcopy.deepcopyfor nested data. - Modifying a list while looping over it skips items. Loop over a copy or build a new list.
- A late-binding closure in a loop sees the final value of the loop variable. Bind it with a default argument:
lambda i=i: i.