Tuples & Sets¶
Two more collection types — each with a specific job.
Tuples — ordered, immutable lists¶
Use () instead of [].
point = (3, 4)
colors = ("red", "green", "blue")
person = ("Alice", 25, "Mumbai")
empty = ()
single = (5,) # NOTE: trailing comma is required for one-item tuple
print(point, colors, person, empty, single)
When to use a tuple¶
- Group related values that shouldn't change: coordinates, dates, RGB colors.
- Function returns multiple values (it's actually returning a tuple).
- Dictionary keys — tuples can be keys (lists can't).
- A tiny bit faster than lists for read-only data.
Tuple operations¶
t = (10, 20, 30, 40, 50)
print(t[0]) # 10 — indexing works
print(t[-1]) # 50
print(t[1:4]) # (20, 30, 40) — slicing works
print(len(t)) # 5
print(20 in t) # True
# These FAIL because tuples are immutable:
# t[0] = 99 # TypeError
# t.append(60) # AttributeError
Unpacking¶
The Pythonic way to destructure a tuple:
point = (3, 4)
x, y = point
print(x, y) # 3 4
# Swap with unpacking
a, b = 1, 2
a, b = b, a
print(a, b) # 2 1
# Star unpacking — collect the rest
first, *middle, last = (1, 2, 3, 4, 5)
print(first, middle, last) # 1 [2, 3, 4] 5
Named tuples — readable tuples¶
When unpacking gets confusing, give fields names:
from collections import namedtuple
Point = namedtuple("Point", ["x", "y"])
p = Point(3, 4)
print(p.x, p.y) # 3 4
print(p) # Point(x=3, y=4)
# Still supports tuple operations
print(p[0], p[1]) # 3 4
x, y = p
print(x, y) # 3 4
Sets — unique, unordered collections¶
Use {} for set literals (but {} alone is an empty dict — use set() for an empty set).
fruits = {"apple", "banana", "cherry"}
empty_set = set()
mixed = {1, "hello", 3.14, True}
print(fruits, empty_set, mixed)
Two key properties of sets¶
- No duplicates — duplicates get silently dropped.
- No order — items have no index.
# Duplicates removed automatically
nums = {1, 2, 2, 3, 3, 3, 4}
print(nums) # {1, 2, 3, 4}
# Remove duplicates from a list
items = [1, 2, 2, 3, 3, 3, 4, 5, 5]
unique = list(set(items))
print(unique) # [1, 2, 3, 4, 5] (order not guaranteed)
Adding / removing¶
s = {1, 2, 3}
s.add(4)
print(s) # {1, 2, 3, 4}
s.update([5, 6, 7]) # add many
print(s)
s.remove(7) # raises KeyError if not present
s.discard(99) # silent if not present
print(s)
popped = s.pop() # remove and return ARBITRARY element
print("popped:", popped)
Membership check — sets are FAST¶
big_set = set(range(1_000_000))
# `x in set` is O(1) — instant, no matter the size
print(999_999 in big_set) # True
# Compare to list: `x in list` is O(n) — slow on big lists
When checking many in queries, use a set, not a list.
Set operations — union, intersection, difference¶
These are the math operations from set theory:
a = {1, 2, 3, 4}
b = {3, 4, 5, 6}
print(a | b) # union {1, 2, 3, 4, 5, 6}
print(a & b) # intersection {3, 4}
print(a - b) # difference {1, 2} (in a but not in b)
print(a ^ b) # symmetric diff {1, 2, 5, 6} (in either but not both)
# Subset / superset
print({1, 2}.issubset(a)) # True
print(a.issuperset({1, 2})) # True
Frozensets — immutable sets¶
fs = frozenset([1, 2, 3])
print(fs)
# fs.add(4) # AttributeError — frozensets can't be modified
# Can be used as dict keys / inside another set
nested = {fs, frozenset([4, 5, 6])}
print(nested)
Quick comparison¶
| Property | list | tuple | set |
|---|---|---|---|
| Syntax | [1,2] |
(1,2) |
{1,2} |
| Ordered? | yes | yes | no |
| Indexed? | yes | yes | no |
| Mutable? | yes | no | yes (but frozenset no) |
| Duplicates? | yes | yes | no |
| Fast membership? | slow O(n) | slow O(n) | fast O(1) |
| Use when | order matters | grouping constants | uniqueness or fast lookup |
Mini-project — find common friends¶
alice_friends = {"Bob", "Charlie", "Diana", "Eve"}
bob_friends = {"Alice", "Charlie", "Frank", "Diana"}
mutual = alice_friends & bob_friends
print("Mutual friends:", mutual)
alice_only = alice_friends - bob_friends
print("Alice-only friends:", alice_only)
all_friends = alice_friends | bob_friends
print("Everyone:", all_friends)
Practice¶
Make this print {1, 2, 5, 6} (symmetric difference)
Expected: {1, 2, 5, 6}
Quiz — Quick check¶
What you remember
Q1. Which is NOT a property of a set?
- Unordered
- No duplicates
- Fast membership check
- Items are accessed by index
Why: Sets have no positional order, so
my_set[0]is aTypeError. If you need indexing, convert to a list first or use a list.
Q2. What does (5,) represent?
- A syntax error
- A list of one element
- A tuple with one element
- The number 5 wrapped in parens
Why: The trailing comma is required for a one-element tuple.
(5)is just the number 5 in parentheses — Python treats the parens as grouping.
Q3. Checking x in big_set vs x in big_list — which is faster?
-
in big_setis dramatically faster (O(1) vs O(n)) -
in big_listis faster - Same speed
- Depends on whether
xis present
Why: Sets are hash tables — checking membership takes constant time regardless of size. Lists must scan front-to-back. For 1 million items, set is ~1,000,000× faster.
Common doubts¶
Tuple or list — which should I use?
Tuple when the size and content are fixed (coordinates, RGB color, a date tuple). List when items will be added, removed, or mutated. Tuples are also slightly faster to create and can be used as dict keys; lists can't.
Why is {} an empty dict, not an empty set?
Historical: dicts came first. {} is reserved for empty dict. For an empty set you must write set(). {1, 2, 3} is a set; {"key": "value"} is a dict — the contents decide.
Are sets unordered? Even in Python 3.7+?
Yes, sets remain unordered. Python 3.7+ made dicts preserve insertion order, but sets do not. If you need a "set" that keeps order, the workaround is a dict with None values: dict.fromkeys(items).