Collections & Comprehensions
list, dict, set, tuple — and the syntax that makes them sing.
Collections & Comprehensions
The four core collections — list, dict, set, tuple — plus the syntax that turns most loops into one-liners.
list
Ordered, mutable, indexable.
xs = [1, 2, 3]
xs[0] # 1
xs[-1] # 3 (negative indexes count from the end)
xs[1:3] # [2, 3] (slice)
xs.append(4)
xs.extend([5, 6])
xs.pop() # remove + return last
xs.insert(0, 0) # insert at index
xs.sort()
sorted(xs) # returns NEW sorted list, doesn't mutate
xs.reverse()
len(xs)
Slicing also accepts a step: xs[::2] (every other), xs[::-1] (reversed copy).
dict
Key→value, fast lookup, ordered (insertion order, since 3.7).
d = {"name": "Alice", "age": 30}
d["name"] # "Alice"
d.get("missing") # None — no exception
d.get("missing", 0) # 0 — fallback
d["email"] = "a@x.com"
del d["age"]
"name" in d # True
d.keys() / d.values() / d.items()
Merge two dicts (3.9+): d3 = d1 | d2. Or unpack: {**d1, **d2}.
set
Unordered, unique, fast membership.
s = {1, 2, 3}
s.add(4)
s.discard(2) # remove if present, no error if missing
3 in s # True
a | b # union
a & b # intersection
a - b # difference
a ^ b # symmetric difference
set() for an empty set — {} is an empty dict.
tuple
Like a list, but immutable. Used for fixed-size groups.
point = (10, 20)
x, y = point # destructure
point[0] # 10
point[0] = 99 # TypeError — tuples are immutable
Single-element tuple needs the trailing comma: (5,) is a tuple, (5) is just 5.
Comprehensions
The Python superpower. A list comprehension turns a for + if + append into one expression:
squares = [x * x for x in range(10)]
evens = [x for x in xs if x % 2 == 0]
flat = [x for row in matrix for x in row] # nested
Dict and set comprehensions exist too:
char_counts = {ch: text.count(ch) for ch in set(text)}
unique_lower = {s.lower() for s in strings}
Generator expressions use () instead of [] and produce values lazily — no list is built:
total = sum(x * x for x in numbers) # no intermediate list
When NOT to comprehension
If the comprehension has side effects (mutation, I/O, anything that's not building a value), write a regular loop. Comprehensions should be expressions, not procedures:
# Bad — comprehension used for the side effect.
[print(x) for x in xs]
# Good.
for x in xs:
print(x)
defaultdict, Counter
The standard library has two collections that come up constantly:
from collections import defaultdict, Counter
# defaultdict — auto-creates the value when a key is missing.
groups = defaultdict(list)
for user in users:
groups[user.team].append(user)
# Counter — multiset; tally occurrences.
counts = Counter(words)
counts.most_common(3) # [('the', 42), ...]
Big-O cheat sheet
| Operation | list | dict | set |
|---|---|---|---|
| Index / key lookup | O(1) | O(1) avg | — |
x in coll |
O(n) | O(1) avg | O(1) avg |
| Append / add | O(1) amortised | O(1) avg | O(1) avg |
| Insert at front | O(n) | — | — |
| Sort | O(n log n) | — | — |
if x in some_list inside a loop is the most common O(n²) bug. Convert to a set first.