Can you write this from memory?
Create an empty list called items
If you hesitate on Python's "append vs extend" or whether to use dict.get() vs d[key], this page is for you.
Here you'll find a quick "which collection should I use?" guide, the core methods, common pitfalls (with fixes), and interview-style examples like frequency counting.
Use it as a refresher before coding sessions or interviews.
| Need | Use | Why |
|---|---|---|
| Ordered sequence, may change | list | Append, pop, slice—general workhorse |
| Key → value lookup | dict | O(1) access by key |
| Uniqueness / fast "is X in here?" | set | O(1) membership, auto-dedupe |
| Fixed record / hashable key | tuple | Immutable, so usable as dict key |
For a quick copy-paste reference of dict operations, see the Python dictionary methods cheat sheet.
| Operation | list | dict | set |
|---|---|---|---|
| Access by index | O(1) | — | — |
| Access by key | — | O(1) avg | — |
Search (x in) | O(n) | O(1) avg | O(1) avg |
| Append/add | O(1) | O(1) avg | O(1) avg |
| Insert at index | O(n) | — | — |
| Delete by value | O(n) | O(1) avg | O(1) avg |
Key insight: If you're doing x in collection frequently, switch from list to set for O(1) lookups.
Here's the rule:
append(x)adds one item to the list—even if that item is itself a list.extend(xs)unpacks the iterable and adds each element.
nums = [1, 2]
nums.append([3, 4]) # → [1, 2, [3, 4]] (nested!)
nums = [1, 2]
nums.extend([3, 4]) # → [1, 2, 3, 4] (flat)
Memory trick: "append appends one thing, extend extends by many."
# Raises KeyError if missing:
value = config["timeout"]
# Returns default if missing:
value = config.get("timeout", 30)
Use d[key] when a missing key is a bug—you want the error.
Use get(key, default) when missing keys are expected (optional config, sparse data).
For insert-if-missing patterns, use setdefault():
counts.setdefault(word, 0)
counts[word] += 1
Or use collections.defaultdict to avoid the boilerplate entirely. When you find yourself constructing complex nested data structures step by step, that's a sign the Builder design pattern may be a good fit.
# In-place sort (modifies original, returns None):
nums = [3, 1, 2]
nums.sort() # nums is now [1, 2, 3]
# New sorted list (original unchanged):
nums = [3, 1, 2]
ordered = sorted(nums) # ordered is [1, 2, 3], nums still [3, 1, 2]
Use sort() when you don't need the original order.
Use sorted() when you need both versions, or when sorting non-lists (tuples, generators).
Both accept key= and reverse=:
# Sort by length, descending:
words.sort(key=len, reverse=True)
Word frequency with Counter
from collections import Counter
text = "the quick brown fox jumps over the lazy dog"
counts = Counter(text.split())
print(counts.most_common(3)) # [('the', 2), ('quick', 1), ('brown', 1)]
Group items by key
from collections import defaultdict
orders = [{"customer": "alice", "total": 50}, {"customer": "bob", "total": 30}, {"customer": "alice", "total": 20}]
by_customer = defaultdict(list)
for order in orders:
by_customer[order["customer"]].append(order)
# {'alice': [{...}, {...}], 'bob': [{...}]}
Dedupe while preserving order
seen = set()
unique = []
for x in items:
if x not in seen:
seen.add(x)
unique.append(x)
Or in Python 3.7+, use dict.fromkeys():
unique = list(dict.fromkeys(items))
For a more concise approach, comprehensions let you build filtered or transformed collections in a single expression.
Merge dicts (Python 3.9+)
merged = defaults | overrides # overrides wins on conflict
For earlier versions: {**defaults, **overrides}
Safe delete from dict
# pop returns the value (or default), no KeyError:
removed = d.pop("key", None)
# del raises KeyError if missing:
if "key" in d:
del d["key"]
1. append vs extend confusion
# Bug: wanted flat list, got nested
result = []
result.append(get_items()) # oops, nested list!
# Fix:
result.extend(get_items())
2. Modifying list while iterating
# Bug: skips items or crashes
for x in items:
if should_remove(x):
items.remove(x)
# Fix: iterate over a copy
for x in items[:]:
if should_remove(x):
items.remove(x)
# Or: use comprehension
items = [x for x in items if not should_remove(x)]
3. Mutable dict key
# Bug: TypeError: unhashable type 'list'
cache = {[1, 2]: "value"}
# Fix: use tuple
cache = {(1, 2): "value"}
4. The single-element tuple trap
not_a_tuple = (42) # just 42
actually_tuple = (42,) # tuple with one element
When to Use Python Collections: Lists, Dicts, Sets & Tuples
- Use **lists** for ordered sequences, stacks/queues, and "do this in order" workflows.
- Use **dicts** for fast lookup by key, structured records, grouping, and counting.
- Use **sets** for uniqueness, deduping, and fast membership checks (`x in s` is O(1)).
- Use **tuples** for fixed "record-like" data, multi-return values, and hashable dict keys.
Check Your Understanding: Python Collections: Lists, Dicts, Sets & Tuples
Count the frequency of words in a sentence.
Use a dict (or `collections.Counter`). Loop once (O(n)) and increment counts. Mention why dict lookups are O(1) average, and why Counter is concise with `most_common()`.
What You'll Practice: Python Collections: Lists, Dicts, Sets & Tuples
Common Python Collections: Lists, Dicts, Sets & Tuples Pitfalls
- Confusing `append` (one item) vs `extend` (many items)—visualize the difference
- KeyError when accessing missing dict keys—use `get()` or `setdefault()`
- Modifying a list while iterating over it—iterate over a copy or use comprehension
- Using a mutable type (list, dict) as a dict key or set item—use tuple instead
- Creating a "not-a-tuple" by forgetting the comma: `(x)` is just `x`, use `(x,)`
Python Collections: Lists, Dicts, Sets & Tuples FAQ
append() or extend()?
`append(x)` adds one item (even if x is a list—it becomes a nested element). `extend(xs)` adds every element from an iterable.
dict.get() or d[key]?
Use `d[key]` when missing keys are a bug (you want KeyError). Use `get(key, default)` when missing keys are expected and you have a sensible fallback.
List or tuple?
Use list for mutable sequences. Use tuple for fixed, immutable records or when you need a hashable value (e.g., dict key).
Why use set instead of list?
Set membership checks (`x in s`) are O(1) average—much faster than scanning a list for large inputs.
When should I use collections.Counter?
When you're counting things. It's a dict subclass with helpful methods like `most_common()` and arithmetic operators.
sort() or sorted()?
`list.sort()` sorts in-place and returns None. `sorted(iterable)` returns a new sorted list, leaving the original unchanged.
What are the built-in collection types in Python?
Python has four built-in collection types: lists (ordered, mutable), tuples (ordered, immutable), dicts (key-value mapping), and sets (unordered, unique items). The `collections` module adds specialized types like `defaultdict`, `Counter`, `deque`, and `OrderedDict`.
Python Collections: Lists, Dicts, Sets & Tuples Syntax Quick Reference
xs.append([1, 2]) # one nested list
xs.extend([1, 2]) # two flat itemsvalue = my_dict.get("key", "default")from collections import Counter
counts = Counter(words)
counts.most_common(3)if item in my_set: # O(1) lookup
...x, y = point
first, *rest = itemscommon = a & b # intersection
all_items = a | b # unionremoved = d.pop("key", None) # no KeyErrorfrom collections import defaultdict
groups = defaultdict(list)
for item in items:
groups[item.category].append(item)nums.sort() # in-place, returns None
new_list = sorted(nums) # returns new listPython Collections: Lists, Dicts, Sets & Tuples Sample Exercises
Create a list called items containing "", "default", "test"
items = ["", "default", "test"]Check if "" is in items
"" in itemsExtend items with items from new_items
items.extend(new_items)+ 83 more exercises
Copy-ready syntax examples for quick lookup
Further Reading
- GDScript Dictionary map() and map_in_place12 min read