A Python set is the collection type you reach for when uniqueness matters more than order. Unlike a list, which preserves the sequence of every item including duplicates, a set keeps each distinct value exactly once and makes no promise about the order in which those values are stored. If you have a list of a thousand email addresses with many repeats and you need to know which distinct addresses appear, passing that list to the set constructor gives you the answer in a single operation. The duplicates are discarded, the order is not preserved, and what remains is the set of unique values.
Sets occupy a distinct place among the four collection types covered in the Python collections explained overview. They are mutable like lists, unordered like the keys of dictionaries before Python 3.7, and they enforce uniqueness like dictionary keys. In fact, sets are implemented using the same hash-table data structure that dictionaries use for their keys. This shared implementation is why membership testing in a set runs in constant time regardless of the set's size, and why set elements must be hashable, just like dictionary keys.
Creating sets
You create a set by writing comma-separated values inside curly braces, or by calling the set constructor on any iterable. The curly-brace syntax is the most common for small, known sets of values. Python automatically removes any duplicates you include.
primes = {2, 3, 5, 7, 11}
letters = set("abracadabra")Passing the string "abracadabra" to the set constructor produces a set of the unique letters: a, b, r, c, and d. The repeated characters appear only once in the result. This pattern, converting an iterable with duplicates into a set to extract the distinct values, is one of the most common set use cases.
The empty set requires the set constructor with no arguments. Writing a pair of empty curly braces creates an empty dictionary, not an empty set. This is a historical quirk of Python's syntax: curly braces were used for dictionaries before sets were added to the language, so the empty brace syntax was already taken. Remembering that set() makes an empty set while {} makes an empty dictionary is one of the first set-related facts every beginner memorizes.
Why sets are unordered
When you print a set, the elements may appear in a different order than you inserted them. This is not a bug; it is a consequence of the hash-table implementation that gives sets their speed. Python places each element into a slot determined by a hash function applied to the element's value, and it makes no effort to preserve insertion order. The order you see when printing is an artifact of the hash values and the internal table layout.
The lack of ordering means sets do not support indexing or slicing. You cannot write my_set[0] to get the first element because there is no first element. You cannot slice a set because there is no meaningful sequence to slice. If you need to access elements by position, convert the set to a list first, but be aware that the resulting order is arbitrary and may differ between runs of the same program.
This unordered nature is the tradeoff. In exchange for giving up positional access, you get constant-time membership testing and automatic deduplication. For the common task of checking whether a value belongs to a known collection, a set is dramatically faster than a list once the collection grows beyond a few dozen items. The article on Python collection membership testing explores this performance difference in detail.
What can and cannot go in a set
Every element in a set must be hashable, which in practice means it must be immutable. Numbers, strings, and tuples are hashable and can be set elements. Lists, dictionaries, and plain sets are mutable and cannot be set elements. Python enforces this at runtime: attempting to add a list to a set raises a TypeError.
Tuples deserve special attention because they can contain mutable objects. A tuple of integers like (1, 2, 3) is fully hashable and perfectly valid as a set element. A tuple containing a list like (1, [2, 3]) is not hashable because the inner list is mutable, and attempting to add such a tuple to a set will fail. The hashability of a tuple depends on the hashability of everything inside it.
This restriction on set elements is the same restriction that applies to dictionary keys. Both data structures use the same hashing mechanism, and both refuse to store objects whose hash value could change over their lifetime. For scenarios where you need a set-like collection of mutable objects, the article on choosing the right Python collection type covers alternatives and workarounds.
When sets outperform lists
The headline advantage of a set is membership testing speed. Checking whether a value is in a list requires scanning the list from the beginning until a match is found, which takes time proportional to the list's length. Checking whether a value is in a set computes the hash of the value, jumps directly to the relevant slot in the hash table, and checks only that one position. The time is constant regardless of how many items the set contains.
For a program that repeatedly checks membership against a large collection, the difference is dramatic. Filtering a million-row dataset against an allowlist of ten thousand IDs stored in a list might take minutes because each check scans thousands of entries. The same filter using a set completes in under a second because each check is a single hash-table lookup. This performance pattern is why sets are the default data structure for lookups in production Python code.
The next article covers adding and removing set items in Python, where you will learn how to populate a set dynamically, remove specific elements, and safely handle the case where the element you want to remove might not exist.
Rune AI
Key Insights
- A set is an unordered collection of unique, hashable items created with curly braces or the set() constructor.
- Sets automatically ignore duplicates and are the fastest way to test membership in Python.
- Set elements must be immutable; you cannot store lists or dictionaries inside a set.
- Create an empty set with set(), not {}, because empty curly braces create a dictionary.
- Sets are ideal for removing duplicates, membership testing, and mathematical set operations.
Frequently Asked Questions
What is a Python set?
Why would I use a set instead of a list?
Can a set contain a list?
Conclusion
Sets are the tool for uniqueness and speed. They trade ordering and indexing for the ability to discard duplicates automatically and test membership in constant time. Understanding sets completes your picture of Python's four core collection types.
More in this topic
Define and Call Python Functions
Learn the exact syntax for defining and calling Python functions with the def keyword, including naming rules, the function body, and how the call stack works.
Python Function Parameters and Arguments
Learn the difference between parameters and arguments, how to pass values by position and by keyword, and the rules for default parameter values.
Python Functions Explained
Learn what Python functions are, why they matter for organizing code, and how they form the foundation of non-trivial programs.