Python — Data Structures
Python provides four built-in data structures: lists, tuples, dictionaries, and sets. Each has different characteristics for mutability, ordering, and performance.
Lists are ordered, mutable, and can contain heterogeneous elements. They are implemented as dynamic arrays.
| 1 | # Creation |
| 2 | empty = [] |
| 3 | nums = [1, 2, 3, 4, 5] |
| 4 | mixed = [1, "hello", 3.14, True] |
| 5 | nested = [[1, 2], [3, 4, 5]] |
| 6 | |
| 7 | # From other iterables |
| 8 | list("abc") # → ['a', 'b', 'c'] |
| 9 | range(5) # → range(0, 5) (lazy) |
| 10 | list(range(5)) # → [0, 1, 2, 3, 4] |
| 11 | |
| 12 | # Indexing (0-based) |
| 13 | print(nums[0]) # → 1 |
| 14 | print(nums[-1]) # → 5 (last element) |
| 15 | print(nums[-2]) # → 4 (second from last) |
| 16 | |
| 17 | # Slicing [start:stop:step] |
| 18 | print(nums[1:3]) # → [2, 3] |
| 19 | print(nums[:3]) # → [1, 2, 3] |
| 20 | print(nums[::2]) # → [1, 3, 5] |
| 21 | print(nums[::-1]) # → [5, 4, 3, 2, 1] (reversed) |
| 22 | |
| 23 | # Methods |
| 24 | nums.append(6) # add to end → [1,2,3,4,5,6] |
| 25 | nums.extend([7, 8]) # merge → [1,2,3,4,5,6,7,8] |
| 26 | nums.insert(0, 0) # insert at position → [0,1,2,3,4,5,6,7,8] |
| 27 | nums.pop() # remove & return last → 8 |
| 28 | nums.pop(0) # remove & return at index → 0 |
| 29 | nums.remove(3) # remove first occurrence of 3 |
| 30 | nums.clear() # remove all |
| 31 | |
| 32 | # Searching |
| 33 | nums = [1, 2, 3, 2, 4] |
| 34 | print(nums.index(2)) # → 1 (first occurrence) |
| 35 | print(nums.count(2)) # → 2 (how many times) |
| 36 | print(5 in nums) # → False (membership) |
| 37 | |
| 38 | # Ordering |
| 39 | nums.sort() # ascending in-place |
| 40 | nums.sort(reverse=True) # descending in-place |
| 41 | sorted(nums) # returns new sorted list |
| 42 | nums.reverse() # reverse in-place |
| 43 | |
| 44 | # Copying |
| 45 | copy1 = nums.copy() # shallow copy |
| 46 | copy2 = nums[:] # shallow copy via slice |
| 47 | import copy |
| 48 | deep = copy.deepcopy(nested) # deep copy for nested |
Tuples are ordered, immutable sequences. They are fixed-size and can be used as dictionary keys (unlike lists).
| 1 | # Creation |
| 2 | empty = () |
| 3 | single = (1,) # trailing comma required! |
| 4 | coords = (10, 20) |
| 5 | named = ("Alice", 30, "Engineer") |
| 6 | |
| 7 | # Parentheses optional (tuple packing) |
| 8 | point = 10, 20 |
| 9 | |
| 10 | # Tuple unpacking (destructuring) |
| 11 | x, y = point |
| 12 | print(x) # → 10 |
| 13 | |
| 14 | # Swapping via tuple |
| 15 | a, b = b, a |
| 16 | |
| 17 | # Unpacking with * |
| 18 | first, *rest = [1, 2, 3, 4] |
| 19 | print(first) # → 1 |
| 20 | print(rest) # → [2, 3, 4] |
| 21 | |
| 22 | # Named tuples (like lightweight objects) |
| 23 | from collections import namedtuple |
| 24 | Point = namedtuple("Point", ["x", "y"]) |
| 25 | p = Point(10, y=20) |
| 26 | print(p.x) # → 10 (attribute access) |
| 27 | print(p[0]) # → 10 (index access) |
| 28 | px, py = p # unpacking |
| 29 | |
| 30 | # When to use tuples |
| 31 | # - Fixed collections (coordinates, RGB values) |
| 32 | # - Dictionary keys (since immutable) |
| 33 | # - Function return values |
| 34 | # - Faster than lists for iteration |
info
Dictionaries store key-value mappings. Keys must be hashable (immutable). Insertion order is preserved since Python 3.7.
| 1 | # Creation |
| 2 | empty = {} |
| 3 | user = {"name": "Alice", "age": 30, "active": True} |
| 4 | |
| 5 | # Dict constructor |
| 6 | dict(name="Bob", age=25) # keyword args |
| 7 | dict([("a", 1), ("b", 2)]) # from pairs |
| 8 | {x: x**2 for x in range(3)} # comprehension |
| 9 | |
| 10 | # Access |
| 11 | print(user["name"]) # → Alice (KeyError if missing) |
| 12 | print(user.get("email")) # → None (safe) |
| 13 | print(user.get("email", "N/A")) # → N/A with default |
| 14 | |
| 15 | # Membership |
| 16 | print("name" in user) # → True |
| 17 | print("email" not in user) # → True |
| 18 | |
| 19 | # Modification |
| 20 | user["email"] = "alice@example.com" |
| 21 | user.update({"age": 31, "city": "NYC"}) |
| 22 | |
| 23 | # Removal |
| 24 | del user["active"] # remove key (KeyError if missing) |
| 25 | user.pop("city") # remove and return value |
| 26 | user.popitem() # remove and return last inserted (3.7+) |
| 27 | user.clear() # remove all |
| 28 | |
| 29 | # Iteration |
| 30 | for key in user: # keys |
| 31 | for value in user.values(): # values |
| 32 | for k, v in user.items(): # both |
| 33 | |
| 34 | # Merging |
| 35 | d1 = {"a": 1, "b": 2} |
| 36 | d2 = {"b": 3, "c": 4} |
| 37 | merged = {**d1, **d2} # spread → {"a": 1, "b": 3, "c": 4} |
| 38 | merged = d1 | d2 # pipe operator (3.9+) |
| 39 | |
| 40 | # Default dict — auto-initialize missing keys |
| 41 | from collections import defaultdict |
| 42 | counts = defaultdict(int) # int() gives 0 |
| 43 | counts["a"] += 1 |
| 44 | |
| 45 | # Counter — count hashable items |
| 46 | from collections import Counter |
| 47 | freq = Counter("abracadabra") |
| 48 | print(freq) # → Counter({'a': 5, 'b': 2, 'r': 2, 'c': 1, 'd': 1}) |
| 49 | print(freq.most_common(2)) # → [('a', 5), ('b', 2)] |
Sets are unordered collections of unique, hashable elements. They support mathematical set operations.
| 1 | # Creation |
| 2 | empty = set() # NOT {} — that's a dict |
| 3 | numbers = {1, 2, 3, 4, 5} |
| 4 | from_list = set([1, 2, 2, 3]) # → {1, 2, 3} (deduped) |
| 5 | |
| 6 | # Set comprehension |
| 7 | evens = {x for x in range(10) if x % 2 == 0} |
| 8 | |
| 9 | # Basic operations |
| 10 | s = {1, 2, 3} |
| 11 | s.add(4) # → {1, 2, 3, 4} |
| 12 | s.remove(4) # → {1, 2, 3} (KeyError if missing) |
| 13 | s.discard(99) # → {1, 2, 3} (no error if missing) |
| 14 | s.pop() # remove & return arbitrary element |
| 15 | s.clear() # remove all |
| 16 | |
| 17 | # Membership — O(1) average |
| 18 | print(2 in {1, 2, 3}) # → True |
| 19 | |
| 20 | # Set operations |
| 21 | a = {1, 2, 3, 4} |
| 22 | b = {3, 4, 5, 6} |
| 23 | |
| 24 | print(a | b) # union → {1, 2, 3, 4, 5, 6} |
| 25 | print(a & b) # intersection → {3, 4} |
| 26 | print(a - b) # difference → {1, 2} |
| 27 | print(a ^ b) # symmetric diff → {1, 2, 5, 6} |
| 28 | |
| 29 | # Comparison |
| 30 | print({1, 2} <= {1, 2, 3}) # subset → True |
| 31 | print({1, 2, 3} >= {1, 2}) # superset → True |
| 32 | print({1, 2}.isdisjoint({3, 4})) # → True |
| 33 | |
| 34 | # Frozen set — immutable hashable set |
| 35 | fs = frozenset([1, 2, 3]) # can be dict key or in set |
best practice
The collections module provides specialized data structures beyond the built-ins.
| 1 | from collections import ( |
| 2 | defaultdict, Counter, namedtuple, |
| 3 | deque, OrderedDict, ChainMap |
| 4 | ) |
| 5 | |
| 6 | # deque — double-ended queue (fast appends/pops both ends) |
| 7 | dq = deque([1, 2, 3], maxlen=5) |
| 8 | dq.append(4) # right |
| 9 | dq.appendleft(0) # left |
| 10 | dq.pop() # from right |
| 11 | dq.popleft() # from left |
| 12 | |
| 13 | # OrderedDict — remembers insertion order (dict does this now, but |
| 14 | # OrderedDict has extra methods like move_to_end) |
| 15 | od = OrderedDict() |
| 16 | od["a"] = 1 |
| 17 | od["b"] = 2 |
| 18 | od.move_to_end("a") # move "a" to the end |
| 19 | |
| 20 | # ChainMap — combine multiple dicts into one view |
| 21 | d1 = {"a": 1, "b": 2} |
| 22 | d2 = {"b": 3, "c": 4} |
| 23 | chain = ChainMap(d1, d2) |
| 24 | print(chain["a"]) # → 1 (from d1) |
| 25 | print(chain["b"]) # → 2 (from d1 — first match wins) |
Community
Get help on Slack, Discord or VIP
Stuck on a guide? Join the community and ask.