A Python set is an unordered collection of unique elements — it automatically discards duplicates and provides extremely fast membership testing. Sets are the programmer's equivalent of a mathematical set, supporting union, intersection, and difference operations directly in the language.
How do you create a set in Python?
A set is created with curly braces or the set() constructor. Unlike a dictionary, a set contains only values (no key-value pairs).
# Creating a set with literals
colours = {"red", "green", "blue"}
# Creating from a list — duplicates are discarded automatically
numbers = set([1, 2, 2, 3, 3, 3, 4])
print(numbers) # {1, 2, 3, 4} — order may vary
# Creating an empty set (NOT {}, which creates an empty dictionary)
empty = set()
Notice that printing a set does not guarantee any particular order — sets are unordered. You cannot rely on numbers[0] to retrieve the first element; sets do not support indexing.
What are the core set operations?
| Operation | Syntax | Symbol | What it returns |
|---|---|---|---|
| Union | `A | BorA.union(B)` |
∪ |
| Intersection | A & B or A.intersection(B) |
∩ | Only elements in both A and B |
| Difference | A - B or A.difference(B) |
\ | Elements in A but not in B |
| Symmetric difference | A ^ B or A.symmetric_difference(B) |
Δ | Elements in A or B, but not both |
| Subset test | A <= B or A.issubset(B) |
⊆ | True if every element of A is in B |
maths_students = {"Alice", "Bob", "Carol", "Dave"}
science_students = {"Carol", "Dave", "Eve", "Frank"}
# Union: students in either class
print(maths_students | science_students)
# {'Alice', 'Bob', 'Carol', 'Dave', 'Eve', 'Frank'}
# Intersection: students in both classes
print(maths_students & science_students)
# {'Carol', 'Dave'}
# Difference: maths students NOT in science
print(maths_students - science_students)
# {'Alice', 'Bob'}
These operations mirror set theory in mathematics — if you have studied sets in a maths lesson, the same Venn-diagram logic applies here.
How do you add and remove elements from a set?
colours = {"red", "green", "blue"}
# Add a single element
colours.add("yellow")
# Remove an element — raises KeyError if not found
colours.remove("green")
# Remove an element — does nothing if not found (safer)
colours.discard("purple")
# Remove and return an arbitrary element
popped = colours.pop()
# Clear all elements
colours.clear()
Because sets are mutable, you can add and remove elements. However, the elements themselves must be immutable — you can store integers, strings, and tuples, but not lists or other sets (which are mutable and therefore not hashable).
Why is membership testing so fast in a set?
Testing whether an element is in a set (x in my_set) runs in O(1) average time — it is almost instantaneous regardless of the set's size. By contrast, testing membership in a list (x in my_list) takes O(n) time — Python must scan every element.
This is because sets are implemented as hash tables under the hood. Python computes the element's hash, jumps directly to the relevant bucket, and checks it — no scanning required.
large_set = set(range(1_000_000))
large_list = list(range(1_000_000))
# O(1) — nearly instant
999_999 in large_set
# O(n) — must scan up to one million elements
999_999 in large_list
For programs that repeatedly test membership in a large collection, converting from a list to a set can dramatically improve performance.
When should you use a set instead of a list?
| Scenario | Best choice | Reason |
|---|---|---|
| Store items and look them up often | Set | O(1) membership testing |
| Need to preserve insertion order | List | Sets are unordered |
| Need duplicates | List | Sets discard duplicates |
| Find common elements between two collections | Set | Intersection in O(min(n,m)) |
| Remove duplicates from a list | Set | list(set(my_list)) is idiomatic |
| Access items by index | List | Sets have no index |
A common real-world pattern: load a list of banned usernames from a database, convert it to a set once, then test every incoming login against the set in O(1) rather than O(n).
Frequently asked questions
Why can't you store a list inside a set in Python?
Sets use hashing to store elements, and Python can only hash immutable objects. A list can be modified after creation, so its hash would change — violating the assumption that an object's hash is constant. For the same reason, you cannot store a set inside another set. Use a frozenset (an immutable set) if you need to store a set as an element of another set.
What is the difference between a set and a dictionary in Python?
Both are implemented as hash tables and use curly brace syntax, which causes confusion. A set stores individual values: {"Alice", "Bob"}. A dictionary stores key-value pairs: {"Alice": 90, "Bob": 85}. An empty {} creates a dictionary, not a set — you must write set() for an empty set.
Can a set contain duplicate values?
No. Duplicates are silently discarded when you create a set or add an element that already exists. This property is extremely useful for deduplication: unique_words = set(all_words) removes repeated words from a list in a single line. If you need to count how many times each word appears, use a dictionary (or collections.Counter) instead.
Is a Python set ordered?
No. Sets are unordered — there is no guarantee about the sequence in which elements are stored or printed. From Python 3.7 onwards, dictionaries maintain insertion order, but sets do not. If you need both uniqueness and order, use a dictionary (Python 3.7+) or a combination of a set and a list to track insertion order manually.
Professor Turing at aitutors.me will guide you through set problems with questions, not answers — building your Python skills step by step.