Sets in Python
A Python set is an unordered collection of unique, hashable values created with set() or curly braces, e.g. {1, 2, 3}. Sets remove duplicates automatically and support fast membership checks and math operations like union (|) and intersection (&).
Lists, tuples, and dictionaries cover a lot of ground — but none of them solve one very specific, very common problem: "give me only the unique things, and let me check membership instantly." That is exactly what a set is for.
Picture a set like a bag of marbles where, no matter how many times you toss in the same color, the bag only ever keeps one. Order does not matter, duplicates get thrown out automatically, and checking "is this marble in the bag?" is nearly instant no matter how many marbles are inside. This page covers creating sets, the classic {} trap, set math (union, intersection, difference), and frozenset. Pair it with Dictionaries in Python for the hashtable mechanics sets share.
What you will learn
By the end you can:
- Create a set and know why
{}does not make an empty one - Remove duplicates from a list in a single line
- Add, remove, and safely discard elements
- Use set math — union, intersection, difference, symmetric difference
- Explain why sets have no order and only hold hashable values
Creating a set
Create a set with curly braces or the set() function:
s = {1, 2, 3}
print(s)
# {1, 2, 3}
s2 = set([1, 2, 2, 3, 3, 3])
print(s2)
# {1, 2, 3}Notice every duplicate in s2 simply vanished — a set automatically keeps only one copy of each unique value. That is its entire reason for existing.
Why use a set? Two big reasons
1. Removing duplicates instantly
numbers = [1, 2, 2, 3, 4, 4, 4, 5]
unique = set(numbers)
print(unique)
# {1, 2, 3, 4, 5}One line, done. Want it back as a list? Wrap it: list(unique).
2. Membership checks are incredibly fast
Just like dictionaries, sets use a hashtable internally. Checking x in my_set takes roughly the same tiny amount of time whether the set has 10 items or 10 million — unlike a list, where Python checks every item one by one:
allowed_users = {"asha", "ravi", "mei"}
if "ravi" in allowed_users:
print("Access granted")This is dramatically faster than checking membership in a list once your collection gets large.
Adding and removing elements
s = {1, 2, 3}
s.add(4)
print(s) # {1, 2, 3, 4}
s.remove(2)
print(s) # {1, 3, 4}
s.discard(99) # no error, even though 99 isn't in the set.add() puts one new value in — adding something already present does nothing, since it is already unique. .remove() deletes a value but crashes with a KeyError if that value is not present. .discard() does the same thing but stays silent if the value was never there — use it whenever you are not sure the item exists.
Set math: union, intersection, difference
This is where sets really shine — they directly support the operations you may remember from a Venn diagram:
a = {1, 2, 3, 4}
b = {3, 4, 5, 6}
a | b # union — everything in either set -> {1, 2, 3, 4, 5, 6}
a & b # intersection — only things in both -> {3, 4}
a - b # difference — in a, but NOT in b -> {1, 2}
a ^ b # symmetric difference — in one, not both -> {1, 2, 5, 6}You can also write these as methods, which read closer to English:
a.union(b)
a.intersection(b)
a.difference(b)
a.symmetric_difference(b)A practical example — finding mutual friends between two people:
asha_friends = {"ravi", "mei", "tom", "sara"}
ravi_friends = {"mei", "sara", "asha", "leo"}
mutual = asha_friends & ravi_friends
print(mutual)
# {'mei', 'sara'}No order, no duplicates, ever
Two things to always remember about sets:
- No order. Sets do not remember insertion order, and you cannot access elements by index —
s[0]does not work on a set. - No duplicates, period. A set silently refuses to hold the same value twice, no matter how many times you try to add it.
s = {1, 2, 3}
s.add(2) # nothing happens — 2 is already there
print(s) # {1, 2, 3}Just like dictionary keys, only hashable (immutable) values can go inside a set. Lists can't be set elements, for the same reason they can't be dictionary keys:
s = {[1, 2]}
# TypeError: unhashable type: 'list'Tuples, being immutable, work perfectly fine inside a set.
Looping over a set
fruits = {"apple", "banana", "mango"}
for fruit in fruits:
print(fruit)Works exactly like looping over a list — except there is no guarantee about what order the items come out in.
Set comprehensions
Like list and dictionary comprehensions, you can build a set in one compact line:
squares = {n ** 2 for n in range(1, 6)}
print(squares)
# {1, 4, 9, 16, 25}frozenset: an immutable set
frozenset is a sibling type — exactly like a regular set, except immutable, the way a tuple is to a list. Because it is immutable, it is hashable, meaning a frozenset can be used as a dictionary key or live inside another set (a regular set cannot):
fs = frozenset([1, 2, 3])
fs.add(4)
# AttributeError: 'frozenset' object has no attribute 'add'You won't need this often as a beginner, but it is good to know it exists for exactly the situations where a regular set is not allowed.
Common mistakes
- Writing
{}expecting an empty set — it creates an empty dictionary; useset() - Calling
.remove()on a value that might not exist and getting aKeyError— use.discard()when unsure - Trying to index into a set with
s[0]— sets have no order and no indexing - Putting a list inside a set or as a dictionary key — only hashable (immutable) types are allowed
- Expecting a set to preserve the order items were added in
Why this matters
Sets are the right tool the moment your problem is about uniqueness or fast membership checks — deduplicating data, comparing groups, or checking permissions against an allow-list. Reaching for a set instead of a list in these cases is often the difference between code that scales and code that quietly gets slower as your data grows.
Common questions
How do you create an empty set in Python?
Use set(). Writing {} creates an empty dictionary instead, since dictionaries use the same curly-brace syntax and claimed it first.
How do you remove duplicates from a list in Python?
Convert the list to a set, which automatically discards duplicates: unique = set(my_list). Wrap it in list(unique) if you need a list back.
What is the difference between union and intersection in Python sets?
Union (a | b) combines everything in either set. Intersection (a & b) keeps only elements that appear in both sets.
What is the difference between remove() and discard() in Python sets?
remove(value) raises a KeyError if the value isn't in the set. discard(value) does the same removal but stays silent if the value doesn't exist, making it safer when you're unsure.
Can you use a list as an element of a Python set?
No. Sets can only hold hashable (immutable) values, and lists are mutable, so adding one raises TypeError: unhashable type: 'list'. Tuples work fine since they're immutable.
What is a frozenset in Python?
A frozenset is an immutable version of a set. Because it can't be changed, it's hashable, so unlike a regular set, a frozenset can be used as a dictionary key or stored inside another set.
Explore
Related topics
Keep going — these sit next to this concept in a real learning path.
Dictionaries in Python
The hashtable mechanics that make sets fast, shared with dictionaries.
Lists in Python
Why a list allows duplicates and order, unlike a set.
Tuples in Python
The other immutable, hashable type that can live inside a set.
Data Types in Python
Where set fits among Python's mutable, non-primitive types.
Python course hub
All free Python explainers and the path into Agentic practice.