Tuples and sets
You know lists. Python has two more collection types that solve problems lists cannot. Tuples hold a fixed group of values that will never change. Sets hold only unique values and let you check membership instantly no matter how large the collection gets.
Tuples
A tuple is an ordered group of values that cannot be changed after you create it. Parentheses define a tuple, but they are optional. The comma is what actually makes it a tuple. A single-item tuple requires a trailing comma.
point = (10, 20)
rgb = (255, 128, 0)
dimensions = (1920, 1080)
single = (42,) # trailing comma required for a single-item tuple
also_tuple = 42, 99 # parentheses are optional; the comma makes it a tupleAccess by index works exactly like a list. Trying to change an item raises a TypeError:
point = (10, 20)
point[0] # 10
point[1] # 20
point[-1] # 20
point[0] = 99 # TypeError: 'tuple' object does not support item assignmentWhen to use a tuple
Use a tuple when you have a small group of related values that belong together and will not change. Coordinates (x, y), a colour (r, g, b), a name-score pair ("Alice", 87). The fixed structure signals to anyone reading the code that this group is treated as a single unit.
locations = {}
locations[(40, -74)] = "New York" # tuple as a dict key, works
locations[[40, -74]] = "New York" # list as a dict key, TypeErrorUnpacking
Unpacking pulls values out of a tuple and assigns each to its own name in a single line. The number of names must match the number of values. Use * to capture any remaining items into a list.
point = (10, 20)
x, y = point
print(x) # 10
print(y) # 20
first, *rest = [1, 2, 3, 4, 5]
# first = 1, rest = [2, 3, 4, 5]
head, *middle, tail = [1, 2, 3, 4, 5]
# head = 1, middle = [2, 3, 4], tail = 5Named tuples
A named tuple is a tuple where each position has a name. Instead of remembering that point[0] is the x-coordinate, you write point.x. The values are still immutable; you just get readable attribute names instead of numeric positions.
Named tuple import
namedtuple is in Python's standard library but needs to be imported. The from collections import namedtuple line is the first import in this course. Imports are covered fully in the Modules chapter.
from collections import namedtuple
Point = namedtuple("Point", ["x", "y"])
Player = namedtuple("Player", ["name", "score", "level"])
p = Point(10, 20)
p.x # 10
p.y # 20
alice = Player("Alice", 87, 5)
alice.name # "Alice"
alice.score # 87Sets
A set is a collection of unique values with no guaranteed order. Adding the same value twice does nothing: a set keeps only one copy of each item. Use curly braces for a set with items, or set() to create an empty set.
tags = {"python", "beginner", "tutorial"}
numbers = {1, 2, 3, 4, 5}
empty = set() # NOT {} (that's an empty dict)Adding the same value twice does not change the set:
tags.add("python") # tags is unchanged, "python" is already in itWhen to use a set
Sets are the right tool for three things: removing duplicates from a list, checking quickly whether something is in a large collection, and comparing two groups to find what they share or differ on.
# Remove duplicates from a list
raw = ["cat", "dog", "cat", "bird", "dog", "cat"]
unique = list(set(raw)) # ["cat", "dog", "bird"] (order not guaranteed)# Fast membership check
valid_codes = {"USD", "EUR", "GBP", "JPY"}
code = "EUR"
if code in valid_codes: # instant lookup, even with thousands of codes
print("Valid")Set operations
Sets support the same operations you learned in maths: union (everything in either set), intersection (only what both sets share), and difference (what one has that the other does not). Python uses operator symbols for these, and each has a method equivalent.
a = {1, 2, 3, 4}
b = {3, 4, 5, 6}
a | b # {1, 2, 3, 4, 5, 6} (union: everything in either)
a & b # {3, 4} (intersection: only in both)
a - b # {1, 2} (difference: in a but not b)
b - a # {5, 6} (difference the other way)
a ^ b # {1, 2, 5, 6} (symmetric difference: in one but not both)These also have method forms: .union(), .intersection(), .difference(), .symmetric_difference().
Modifying sets
Sets are mutable. .add() adds one item. .update() adds several at once from any list or other iterable. .remove() deletes an item but raises an error if it is not there. .discard() deletes silently if the item exists and does nothing if it does not.
tags = {"python", "beginner"}
tags.add("tutorial") # add one item
tags.update(["web", "api"]) # add multiple items from any iterable
tags.remove("beginner") # remove, raises KeyError if not found
tags.discard("missing") # remove, no error if not found
tags.pop() # remove and return an arbitrary item
tags.clear() # remove everythingUse .discard() when you are not sure whether the item exists.
Frozen sets
A frozen set is a set you cannot modify after creation. The main reason to use one: frozen sets are hashable, so they can be used as dictionary keys or stored inside other sets.
valid_statuses = frozenset({"active", "paused", "deleted"})
valid_statuses.add("archived") # AttributeError, frozenset is immutableChoosing the right collection
Four types, each with a clear role. Ask what you need to do with the data and the right choice usually becomes obvious.
| list | tuple | set | dict | |
|---|---|---|---|---|
| Ordered | Yes | Yes | No | Yes (insertion order) |
| Mutable | Yes | No | Yes | Yes |
| Duplicates | Yes | Yes | No | No (keys) |
| Access by | Index | Index | n/a | Key |
| Use when | Ordered, changeable sequence | Fixed record | Unique values, fast membership | Key-value lookup |
A quick decision rule:
- Need to look something up by name? → dict
- Need an ordered collection you will modify? → list
- Have a fixed group of related values? → tuple
- Need unique values or fast membership tests? → set
In practice
Using tuples to store fixed records and a set to track unique values:
home = (51.5074, -0.1278) # latitude, longitude
office = (51.5155, -0.0922)
home_lat, home_lon = home
print(f"Home: {home_lat}, {home_lon}")
# Track unique visitors with a set
visitors = set()
visitors.add("alice")
visitors.add("bob")
visitors.add("alice") # already in set, silently ignored
visitors.add("carol")
print(f"Unique visitors: {len(visitors)}")
print(f"alice visited: {'alice' in visitors}")
print(f"dave visited: {'dave' in visitors}")
