☰ Learn Python Tutorial Menu
Tuples and Sets
Written by CSA mentors · Updated 26 Sept 2026 · 4 min read
Here's a question we ask in class. You have last month's list of 38,000 flagged customer IDs and this month's list of 40,000. Which ones are new? Most students start writing a loop inside a loop. That runs for minutes. The right answer runs in a blink, and it uses a type we haven't covered yet. Lists are flexible, but flexibility isn't always what you want. A record like a (date, amount) pair shouldn't be changed by accident, and a collection of customer IDs shouldn't hold duplicates. Python has a type for each job. The tuple (fixed, ordered) and the set (unique, unordered).
Tuples, for fixed records
A tuple is written with parentheses (or just commas). Once created it can't be changed.
islamabad = (33.6844, 73.0479)
record = ("2026-09-24", "Lahore", 2500)
print(record[1]) # Lahore
lat, lon = islamabad # unpacking
print(lat)
record[2] = 3000 # TypeError: 'tuple' object does not support item assignment
Why would anyone want something they can't change? Three reasons.
- Safety. A function that returns a tuple guarantees the caller won't accidentally mutate shared data.
- Dictionary keys. Only immutable values can be dict keys, so a tuple like
("Lahore", "2026-09")works as a key and a list doesn't. - Meaning. A tuple says "this is one record with fixed fields". A list says "this is a sequence that may grow".
A one-element tuple needs a trailing comma, so (5,). Without it, (5) is just the number 5. This one produces a confused face every batch.
You've been using tuples already
divmod(135, 60) returns (2, 15). The swap a, b = b, a builds and unpacks a tuple. Any function that returns several values returns a tuple.
def min_max(values):
return min(values), max(values) # returns a tuple
lo, hi = min_max([120, 95, 140])
print(lo, hi) # 95 140
Named tuples
record[2] tells the reader nothing. collections.namedtuple gives the fields names while keeping tuple behaviour.
from collections import namedtuple
Sale = namedtuple("Sale", ["date", "city", "amount"])
s = Sale("2026-09-24", "Lahore", 2500)
print(s.city, s.amount) # Lahore 2500
print(s) # Sale(date='2026-09-24', city='Lahore', amount=2500)
Sets, for unique values
A set holds each value at most once, has no order, and answers "is it in there?" almost instantly.
cities = {"Lahore", "Multan", "Lahore", "Karachi", "Multan"}
print(cities) # {'Karachi', 'Lahore', 'Multan'} order may vary
print(len(cities)) # 3
cities.add("Quetta")
cities.discard("Multan") # no error if missing (remove() would raise)
print("Lahore" in cities) # True, and very fast even with millions of items
Careful, {} creates an empty dict, not a set. For an empty set write set().
Deduplicating a list
emails = ["a@x.pk", "b@x.pk", "a@x.pk", "c@x.pk", "b@x.pk"]
unique = list(set(emails))
print(len(emails), "->", len(unique)) # 5 -> 3
This loses the original order. When order matters, use list(dict.fromkeys(emails)), which keeps the first occurrence of each.
Set operations
| Operation | Syntax | Question it answers |
|---|---|---|
| Union | a | b | Everyone in either list |
| Intersection | a & b | Who is in both |
| Difference | a - b | In a but not b |
| Symmetric difference | a ^ b | In exactly one of them |
| Subset | a <= b | Is every a in b? |
paid_2025 = {"C001", "C002", "C003", "C007"}
paid_2026 = {"C002", "C003", "C009"}
print(paid_2025 & paid_2026) # {'C002', 'C003'} retained customers
print(paid_2025 - paid_2026) # {'C001', 'C007'} churned
print(paid_2026 - paid_2025) # {'C009'} new
print(paid_2025 | paid_2026) # all five
That's the answer to the opening question. Nested loops over two lists of tens of thousands of IDs take minutes. Two sets and a minus sign take milliseconds. When I review a student's churn script and see a double loop, this is the lesson I send them back to.
Which one do I use?
| You need | Use |
|---|---|
| Ordered items that will grow, shrink or be sorted | list |
| A fixed record of a few fields, or a dict key | tuple |
| Unique values, fast "is it there?", overlaps between groups | set |
| Frozen set usable as a dict key | frozenset |
Two exports, one fraud desk in Karachi: The team gets this month's flagged CNICs from one system and last month's from another. Converting each export to a set and subtracting gives the newly flagged customers in one line, and
&gives the repeat offenders. The same team stores each alert as a tuple(cnic, timestamp, amount)so no downstream script can quietly overwrite the amount.
Quick recap
- Tuples are ordered and immutable. Use them for fixed records, multiple return values and dict keys.
namedtuplegives tuple fields readable names.- Sets hold unique values with no order, and
inchecks are near instant. - Set operations (
&,|,-) answer overlap questions without loops. set()for an empty set.{}is an empty dict.
Try these
- Create a tuple for a Faisalabad shipment (container number, destination port, weight in kg). Unpack it into three variables and print a sentence using them.
- Given two lists of student roll numbers, those who submitted assignment 1 and those who submitted assignment 2, use sets to print who submitted both, who submitted only the first, and how many submitted at least one.
- Remove duplicates from
["Lahore", "lahore", "LAHORE", "Multan"]ignoring case, keeping the first spelling seen.
Lesson 9 of 26
Sign in to track your progress and earn learning points for every lesson you finish.
