๐Ÿ Python

โ† Back to Cheatsheets

A quick-reference for the most commonly used Python features and core data structures. Everything is an object, functions are first-class, and collections are expressive and battle-tested.

Paradigm: Multi-paradigm (OOP, Functional, Procedural) Typing: Dynamic ยท Strong Execution: Interpreted ยท Garbage collected (CPython)
Resources: docs.python.org Standard Types Reference collections module PEP 8 โ€” Style guide Real Python

Variables & Types

โ–ผ

Python is dynamically and strongly typed. Variables are references to objects โ€” type hints provide editor diagnostics without enforcing types at runtime.

Variable Assignment
x = 42
name: str = "Alice"  # type hint annotation
a, b = 1, 2          # multiple assignment
no keyword like var/let; reassignment changes object binding
Primitive Data Types
i = 100               # int (arbitrary precision)
f = 3.14              # float (64-bit IEEE 754)
b = True              # bool (subclass of int)
s = "text"            # str (immutable Unicode)
raw = b"bytes"        # bytes (immutable 8-bit bytes)
n = None              # NoneType (singleton representing null)
Type Checking & Identity
type(x)               # returns type object: <class 'int'>
isinstance(x, (int, float))  # True if x is int or float
x is None             # identity check (compares memory address)
a == b                # equality check (compares values)
always use is to compare against None or bool singletons
Type Conversion (Casting)
int("42") / float(10)
str(100) / bool(1)    # 0, "", [], None are falsy; others truthy
list("abc")           # ['a', 'b', 'c']
Declaring Collection Types
nums: list[int] = []              # empty list  (list() also works)
scores: list[float] = [1.5, 2.0]  # list literal

mapping: dict[str, int] = {}      # empty dict  (dict() also works)
mapping = dict(a=1, b=2)          # from keyword args

unique: set[str] = set()          # empty set โ€” {} creates a dict, not a set!
unique = {"apple", "banana"}      # set literal with values

point: tuple[int, int] = (0, 0)   # fixed-size, heterogeneous
path: tuple[str, ...] = ("a", "b", "c")  # variable-length, homogeneous
single = (42,)                    # one-element tuple โ€” trailing comma required
Type hints (e.g. list[int]) are checked by mypy/pyright, not at runtime. list[int] syntax requires Python 3.9+; use List[int] from typing for earlier versions.

Built-in Functions

โ–ผ

Always available without importing. Prefer them over manual loops โ€” implemented in C and communicate intent clearly.

Print
print("hello", end="\n", sep=" ")
end and sep are optional kwargs
Type & isinstance
type(x)
isinstance(x, (int, float))  # accepts tuple of types
Range
range(5)           # 0, 1, 2, 3, 4          (stop only)
range(2, 7)        # 2, 3, 4, 5, 6          (start, stop โ€” stop is exclusive)
range(0, 10, 2)    # 0, 2, 4, 6, 8          (start, stop, step)
range(10, 0, -1)   # 10, 9, 8, ..., 1       (count down)
list(range(3))     # [0, 1, 2]              (convert to list)
Enumerate
fruits = ["apple", "banana", "cherry"]

for i, fruit in enumerate(fruits):
    print(i, fruit)    # 0 apple / 1 banana / 2 cherry

for i, fruit in enumerate(fruits, start=1):
    print(i, fruit)    # 1 apple / 2 banana / 3 cherry

list(enumerate(fruits))  # [(0,'apple'), (1,'banana'), (2,'cherry')]
yields (index, value) tuples; avoids a manual counter variable
Zip
names  = ["Alice", "Bob", "Carol"]
scores = [95, 82, 78]

# pair elements from two (or more) iterables
list(zip(names, scores))
# [("Alice",95), ("Bob",82), ("Carol",78)]  โ€” stops at shortest

for name, score in zip(names, scores):
    print(f"{name}: {score}")

# build a dict from two parallel lists
d = dict(zip(names, scores))
# {"Alice": 95, "Bob": 82, "Carol": 78}

# unzip โ€” transpose a list of pairs
pairs = [("Alice", 95), ("Bob", 82)]
names2, scores2 = zip(*pairs)
# names2=("Alice","Bob")  scores2=(95,82)

# pad shorter lists instead of stopping
from itertools import zip_longest
list(zip_longest([1, 2, 3], ["a", "b"], fillvalue="-"))
# [(1,'a'), (2,'b'), (3,'-')]
lazy โ€” wrap in list() to materialise. Use zip_longest when lists may differ in length.
Map & Filter
nums = [1, 2, 3, 4, 5]

# map: apply a function to every element
list(map(str, nums))               # ['1','2','3','4','5']
list(map(lambda x: x**2, nums))    # [1, 4, 9, 16, 25]

# filter: keep elements where fn returns True
list(filter(lambda x: x % 2, nums))  # [1, 3, 5] โ€” odd numbers
list(filter(None, [0, 1, "", "ok"]))  # [1, 'ok'] โ€” drops falsy values

# list comprehensions are usually more readable (equivalent):
[x**2 for x in nums]               # same as map
[x for x in nums if x % 2]         # same as filter
Both return lazy iterators โ€” wrap in list() to get a list.
Sorted
nums = [3, 1, 4, 1, 5, 9]
sorted(nums)                  # [1, 1, 3, 4, 5, 9] โ€” new list
sorted(nums, reverse=True)    # [9, 5, 4, 3, 1, 1]

words = ["banana", "fig", "apple"]
sorted(words, key=len)        # ['fig', 'apple', 'banana'] โ€” by length
sorted(words, key=str.lower)  # case-insensitive alphabetical

# list.sort() sorts in-place, returns None:
nums.sort()        # mutates nums directly (no copy)
sorted() returns a new list; list.sort() mutates in-place and returns None.
Any & All
nums = [1, 2, 3, 4, 0]

any(x > 3 for x in nums)    # True  โ€” at least one element > 3
all(x > 0 for x in nums)    # False โ€” 0 fails the check
any([])                      # False โ€” empty iterable
all([])                      # True  โ€” vacuously true

# useful for validation:
all(isinstance(x, int) for x in nums)   # True  โ€” all ints
any(x < 0 for x in nums)                # False โ€” no negatives
any() short-circuits on first True; all() short-circuits on first False.
Len / Min / Max / Sum
len(x) / min(x) / max(x) / sum(x)
min(x, key=fn)  # min/max accept a key= kwarg, same as sorted

Loops & Control Flow

โ–ผ

Python uses indentation for blocks. Loops support optional else clauses that run when the loop completes without a break.

If / Elif / Else
if score >= 90:
    grade = "A"
elif score >= 80:
    grade = "B"
else:
    grade = "C"
status = "pass" if score >= 60 else "fail" # ternary
For / Range Loop
for i in range(5):          # 0..4
    print(i)
for item in container:
    process(item)
While Loop & Else
count = 0
while count < 3:
    count += 1
else:
    print("completed without break")
else block executes only if while condition becomes false (not on break)
Structural Pattern Matching (3.10+)
match command.split():
    case ["quit"]: exit()
    case ["load", filename]: load(filename)
    case _: print("unknown command")
case _ is wildcard default fallback

String Manipulation

โ–ผ

Strings are immutable sequences of Unicode characters. Slicing, transforming, or replacing returns a brand new string.

Accessing Characters & Slicing
s = "Python"
# s[start:stop:step] โ€” all three arguments are optional
s[0]          # 'P'       index 0 (first char)
s[-1]         # 'n'       last char (counts from end)
s[-2]         # 'o'       second to last
s[1:4]        # 'yth'     index 1 up to (not including) 4
s[:3]         # 'Pyt'     from start to index 3
s[2:]         # 'thon'    from index 2 to end
s[-3:]        # 'hon'     last 3 characters
s[::2]        # 'Pto'     every 2nd character (step=2)
s[1:5:2]      # 'yh'      start=1, stop=5, step=2
s[::-1]       # 'nohtyP'  step=-1 walks backwards โ†’ reversed
Slicing works identically on list and tuple. Omitted args default to start=0, stop=len, step=1.
Searching & Inspection
s.find("th")           # starting index (or -1 if missing)
s.rfind("o")           # search starting from the right
s.index("th")          # starting index (raises ValueError if missing)
s.count("o")           # count non-overlapping occurrences
"py" in s.lower()      # membership test (case-insensitive)
s.startswith("Py")     # True (also accepts tuple of prefixes)
s.endswith((".txt", ".md"))  # check multiple extensions
find() returns -1 if missing; index() raises ValueError.
"Updating" & Replacing
# Direct mutation is NOT allowed:
# s[0] = 'J'  --> TypeError: 'str' object does not support item assignment

s.replace("old", "new", count=-1)  # replace occurrences (optional count)
s.removeprefix("pre_")             # remove prefix if present (3.9+)
s.removesuffix(".txt")             # remove suffix if present (3.9+)
s.strip()                          # strip whitespace from both ends
s.lstrip(" _") / s.rstrip(" _")    # strip custom characters
s.lower() / s.upper() / s.title()  # case transforms
All string methods return a new string. Nothing mutates in place.
"Adding", "Inserting" & "Popping"
# "Append" (concatenation):
s = s + " extra"       # concatenation (or s += "...")

# "Insert at index i":
i, insert_str = 2, "XYZ"
s = s[:i] + insert_str + s[i:]

# "Update last character":
s = s[:-1] + "Z"

# "Pop last character":
last_char, s = s[-1], s[:-1]
Slice notation s[:-1] isolates everything except the last character.
Splitting & Joining
"a,b,c".split(",")                 # ['a', 'b', 'c']
"a,b,c".rsplit(",", maxsplit=1)    # ['a,b', 'c'] (split from right)
"line1\nline2".splitlines()        # ['line1', 'line2']
", ".join(["a", "b", "c"])         # "a, b, c" (join sequence with sep)
"42".zfill(5)                      # "00042" (zero-pad)
"hi".center(10, "-")               # "----hi----"
join() is called on the separator string: sep.join(list).
f-strings & Formatting
f"Hello {name!r}"                  # !r=repr, !s=str, !a=ascii
f"Price: ${price:.2f}"             # 2 decimal places: "$19.99"
f"Padded: {val:04d}"               # zero-padded integer: "0007"
f"Percent: {pct:.1%}"              # formatted percentage: "75.0%"
f"{x = }"                          # debug print (3.8+): "x = 42"
f-strings (Python 3.6+) evaluate expressions at runtime and are idiomatic.

Collections

โ–ผ

Python provides expressive core collections: list (sequence), dict (key-value map), set (unique elements), tuple (immutable sequence), and stdlib extras: deque (double-ended queue), heapq (min-heap), namedtuple, Counter, defaultdict.

Lists (list) โ€” Mutable Sequence
lst: list[int] = []        # type-annotated empty list
lst = [1, 2, 3]            # literal; lst = list() also works

lst.append(4)              # add to end
lst.insert(1, 99)          # insert at index
lst.extend([5, 6])         # append multiple items
val = lst.pop()            # remove & return last
val = lst.pop(0)           # remove & return at index
lst.remove(99)             # remove first occurrence by value
lst[0] = 10                # update by index

lst[1:3]                   # slice โ€” returns new list
lst.sort() / lst.reverse() # in-place sort / reverse (return None)
evens = [x for x in lst if x % 2 == 0]  # list comprehension
0-indexed dynamic arrays; preserve insertion order.
Dictionaries (dict) โ€” Key-Value Map
d: dict[str, int] = {}     # type-annotated empty dict
d = {"a": 1, "b": 2}       # literal; dict(a=1, b=2) also works

d["c"] = 3                 # insert or overwrite
d.get("x", 0)              # safe lookup โ€” returns 0 if missing
d.pop("a")                 # remove key, return value
d.pop("a", None)           # same but silent if key is missing
d.keys() / d.values() / d.items()  # live views (not copies)
merged = d1 | d2           # merge โ€” right side wins on conflicts (3.9+)
last = next(reversed(d))   # last inserted key

{k: v for k, v in d.items() if v > 0}  # dict comprehension
Hash map; insertion order preserved (3.7+).
Sets (set) โ€” Unique Unordered Elements
s: set[str] = set()        # empty set โ€” {} creates a dict!
s = {"apple", "banana"}    # set literal with values

s.add("cherry")            # add element
s.discard("missing")       # silent remove โ€” no error if absent
s.remove("apple")          # remove โ€” raises KeyError if missing

a = {1, 2, 3};  b = {2, 3, 4}
a | b    # {1,2,3,4}  union        (in a or b)
a & b    # {2,3}      intersection (in both)
a - b    # {1}        difference   (in a but not b)
a ^ b    # {1,4}      symmetric difference (in a or b, not both)

{x*2 for x in s}           # set comprehension
Hash-based; elements must be hashable (no lists or dicts).
Tuples (tuple) โ€” Immutable Sequence
t: tuple[int, str] = (42, "hi")    # fixed-size, heterogeneous
t: tuple[int, ...] = (1, 2, 3)     # variable-length, homogeneous
single = (42,)                      # one-element โ€” trailing comma required

a, b, c = (1, 2, 3)                # unpacking
first, *mid, last = (1, 2, 3, 4)   # extended unpacking
t_new = t + (4,)                    # new tuple (immutable โ€” no in-place edit)
t[1:3]                              # slicing returns a new tuple
Fixed size and immutable; hashable when all contents are hashable โ€” usable as dict keys.
Deque (deque) โ€” Double-Ended Queue
from collections import deque

dq = deque([1, 2, 3])       # optional maxlen=N caps size (FIFO eviction)
dq.append(4)                # add to right
dq.appendleft(0)            # add to left
val = dq.pop()              # remove & return from right
val = dq.popleft()          # remove & return from left
dq.rotate(1)                # shift right by 1 (negative = left)
list(dq)                    # [0, 1, 2, 3] โ€” convert to list
Use instead of list.pop(0) for front operations โ€” see table for complexity. Ideal for queues, BFS, and sliding windows.
Heap (heapq) โ€” Min-Heap / Priority Queue
import heapq

heap = []
heapq.heappush(heap, 3)     # push
heapq.heappush(heap, 1)
val = heapq.heappop(heap)   # pop min; returns 1
heap[0]                     # peek min without removing
heapq.heapify(lst)          # convert list in-place
heapq.nlargest(2, lst)      # top-2 largest
heapq.nsmallest(2, lst)     # top-2 smallest

# max-heap: negate values
heapq.heappush(heap, -val)
max_val = -heapq.heappop(heap)
Python's heap is a min-heap. Negate values to simulate a max-heap.
Collections Module (Counter, defaultdict & namedtuple)
from collections import Counter, defaultdict, namedtuple

c = Counter("banana")         # Counter({'a': 3, 'n': 2, 'b': 1})
c.most_common(2)              # [('a', 3), ('n', 2)] โ€” top frequencies

dd = defaultdict(list)        # auto-initializes [] for missing keys
dd["fruits"].append("apple")  # safe append without prior key check

Point = namedtuple("Point", ["x", "y"])  # lightweight immutable record
p = Point(1, 2)
p.x / p.y                     # attribute access
x, y = p                      # unpacking like a regular tuple
p._replace(x=10)              # returns a new instance with field changed
Counter tallies frequencies; defaultdict eliminates key existence checks; namedtuple gives tuple fields readable names.

Operations & Time Complexity

Operation list deque heapq set dict tuple str
Access item lst[i] (O(1)) dq[i] (O(n) mid) heap[0] (min, O(1)) Unindexed (next(iter(s))) d[k] / d.get(k) (O(1)) t[i] (O(1)) s[i] (O(1))
Access last item lst[-1] (O(1)) dq[-1] (O(1)) N/A (heap order) Unordered (list(s)[-1]) next(reversed(d)) (O(1)) t[-1] (O(1)) s[-1] (O(1))
Add / Append lst.append(x) (O(1)) dq.append(x) (O(1)) heappush(heap, x) (O(log n)) s.add(x) (O(1)) d[key] = val (O(1)) t = t + (x,) (O(n)) s = s + "x" (O(n))
Add to front lst.insert(0, x) (O(n)) dq.appendleft(x) (O(1)) N/A N/A (unordered) N/A (by key) (x,) + t (O(n)) "x" + s (O(n))
Insert at index lst.insert(i, x) (O(n)) dq.insert(i, x) (O(n)) N/A N/A (unordered) N/A (by key) t[:i] + (x,) + t[i:] (O(n)) s[:i] + "x" + s[i:] (O(n))
Update item lst[i] = val (O(1)) dq[i] = val (O(n) mid) N/A (pop + push) s.discard(o); s.add(n) d[k] = val (O(1)) t[:i] + (v,) + t[i+1:] (O(n)) s.replace(o, n, 1) (O(n))
Remove by value lst.remove(x) (O(n)) dq.remove(x) (O(n)) heap.remove(x); heapify (O(n)) s.remove(x) / discard (O(1)) del d[k] (O(1)) tuple(x for x in t if x!=v) (O(n)) s.replace(sub, "", 1) (O(n))
Pop last lst.pop() (O(1)) dq.pop() (O(1)) heappop(heap) (min, O(log n)) s.pop() (arbitrary, O(1)) d.pop(k) / d.popitem() (O(1)) last, t = t[-1], t[:-1] (O(n)) last, s = s[-1], s[:-1] (O(n))
Pop first lst.pop(0) (O(n)) dq.popleft() (O(1)) N/A N/A N/A N/A N/A
Check existence x in lst (O(n)) x in dq (O(n)) x in heap (O(n)) x in s (O(1)) k in d (O(1)) x in t (O(n)) sub in s (O(n))
Clear / Empty lst.clear() dq.clear() heap.clear() s.clear() d.clear() t = () s = ""
Mutable in-place? Yes Yes Yes (list) Yes Yes No (Immutable) No (Immutable)
Ordered? Yes (0-indexed) Yes (insertion) Partial (heap order) No (Unordered) Yes (Insertion) Yes (0-indexed) Yes (0-indexed)

Classes & OOP

โ–ผ

Python supports single and multiple inheritance with duck typing. @dataclass removes boilerplate for data containers.

Dataclass
from dataclasses import dataclass, field

@dataclass
class Point:
    x: float
    y: float = 0.0
    tags: list = field(default_factory=list)
# auto-generates __init__, __repr__, __eq__; frozen=True for immutability
__str__ vs __repr__
__str__   # human-readable (used by print)
__repr__  # unambiguous (REPL/debug)
# __repr__ is fallback for both if only one is defined
Property
@property
def name(self): return self._name

@name.setter
def name(self, v): self._name = v.strip()
Classmethod vs Staticmethod
@classmethod
def from_string(cls, s):   # receives cls โ€” alternative constructor
    return cls(*s.split(","))

@staticmethod
def validate(x):           # no implicit arg โ€” namespaced utility
    return x > 0

Error Handling

โ–ผ

Catch specific exception types โ€” bare except: silences every error including KeyboardInterrupt.

Try / Except / Finally
try:
    result = risky()
except (TypeError, ValueError) as e:
    print(f"caught: {e}")
else:
    print("no exception")  # runs only if no exception raised
finally:
    cleanup()              # always runs
Raise
raise ValueError("message")
raise  # bare raise re-raises, preserving traceback
Context Manager
with open("file.txt") as f:
    data = f.read()
# calls __enter__ on entry, __exit__ on exit (even after exceptions)

Common Patterns

โ–ผ

Idiomatic Python favours readability and conciseness. Type hints improve editor support and catch bugs early without runtime enforcement.

Walrus Operator (3.8+)
if n := len(data):
    print(f"got {n} items")
# assign and test in one expression
Unpacking
a, *rest, b = [1, 2, 3, 4, 5]
# a=1, rest=[2,3,4], b=5  โ€” works in function args too
Lambda
fn = lambda x, y: x + y
# single-expression anonymous; prefer def for anything more complex
Generator Expression
total = sum(x*x for x in range(100))
# lazy โ€” produces values one at a time, no list in memory
Type Hints
def greet(name: str) -> str:
    return f"Hello {name}"

# Python 3.10+: use X | Y instead of Union[X, Y]
def parse(val: str | None) -> int | None:
    return int(val) if val else None
# use mypy or pyright to enforce โ€” not checked at runtime