Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
A Python set is an unordered collection of distinct, hashable objects. Use sets when you need fast-style membership logic, duplicate removal, or mathematical operations such as union and intersection. Create a populated set with braces or set(iterable); create an empty set with set(), because {} creates an empty dictionary.
What is a set in Python?
The Python tutorial defines a set as “an unordered collection with no duplicate elements.” A set object contains only distinct hashable values, so inserting an existing value has no additional effect.
numbers = {1, 2, 3, 2}
print(numbers) # {1, 2, 3}
print(2 in numbers) # True
Sets are useful for membership checks, removing repeated values, and comparing groups of data. They do not support positional indexing or slicing, and Python makes no ordering guarantee when a set is displayed or iterated. If output order matters, make it explicit with sorted().
Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Clear out junk files and repair common Windows errorsFree Scan →tags = {"python", "api", "web"}
print(sorted(tags)) # deterministic presentation order
Creating sets correctly
Set literals
colors = {"red", "green", "blue"}
ids = {101, 102, 103}
Constructing from an iterable
set() accepts an iterable such as a list, tuple, string, or generator. Duplicate input values are collapsed.
#1 Best Overall
from_iterable = set(["red", "red", "blue"])
print(from_iterable) # {'red', 'blue'}
letters = set("banana")
print(letters) # distinct characters; order is unspecified
Creating an empty set
empty = set()
print(type(empty)) # <class 'set'>
not_a_set = {}
print(type(not_a_set)) # <class 'dict'>
Use set() whenever you need an empty set. Braces without elements are reserved for an empty dictionary.
What can a set contain?
Every element must be hashable. Immutable built-in values such as numbers, strings, tuples (when their contents are hashable), and frozenset qualify. Mutable lists, dictionaries, and ordinary sets do not.
valid = {(1, 2), "text", 42}
# This raises TypeError: unhashable type: 'list'
# invalid = {[1, 2]}
Hashability lets Python place values in the set’s internal structure. A tuple containing a list is also invalid because the tuple’s contents are not all hashable.
frozenset: an immutable set
frozenset has set operations but cannot be changed after creation. Because it is immutable and hashable, it can be nested in another set or used as a dictionary key.
immutable = frozenset([1, 2, 3])
container = {immutable}
lookup = {immutable: "a dictionary value"}
print(immutable)
print(lookup[immutable])
Choose a normal set for a collection you will update. Choose frozenset for a fixed group that must itself be stored in a set or used as a mapping key.
Rank #2
Union, intersection, difference, and symmetric difference
Set operators make group comparisons concise. Given the following sets:
a = {1, 2, 3}
b = {3, 4, 5}
| Operation | Operator | Result | Meaning |
|---|---|---|---|
| Union | a | b |
{1, 2, 3, 4, 5} |
Every value in either set |
| Intersection | a & b |
{3} |
Values common to both |
| Difference | a - b |
{1, 2} |
Values in a but not b |
| Symmetric difference | a ^ b |
{1, 2, 4, 5} |
Values in exactly one set |
union = a | b
common = a & b
only_a = a - b
either = a ^ b
# Named methods express the same operations
common_again = a.intersection(b)
new_values = a.union(b)
removed = a.difference(b)
exclusive = a.symmetric_difference(b)
Named methods are often clearer when an expression combines several operations or when you are passing an iterable rather than writing an operator expression.
Free tools Windows power users keep installed
One-click scans. No signup required.
Subset and superset tests
is_subset = {1, 2} <= a # True
is_superset = a >= {1, 2} # True
strict_subset = {1, 2} < a # True: not equal to a
<= means every element on the left is in the right. The strict form < additionally requires the sets to differ.
Changing a set safely
Add one or many values
items = {"a", "b"}
items.add("c")
items.update(["d", "e"])
print(items)
add() inserts one element. update() consumes an iterable and inserts each of its elements; passing a string therefore adds individual characters.
Remove values
items.discard("missing") # does nothing if absent
# items.remove("missing") # raises KeyError if absent
removed = items.pop() # removes an arbitrary element
items.clear() # removes everything
Use discard() when absence is normal. Use remove() when absence indicates a bug you want to detect. pop() does not promise which element is removed, because sets are unordered; do not use it to retrieve a predictable “first” value.
Set comprehensions
A set comprehension follows the for/if pattern of a list comprehension while producing a set. The result is automatically deduplicated.
words = ["cat", "car", "dog", "cat"]
c_words = {word for word in words if word.startswith("c")}
print(c_words) # {'cat', 'car'}
You can transform values as well as filter them:
raw = [" Alice ", "alice", "Bob"]
names = {name.strip().lower() for name in raw}
print(names) # {'alice', 'bob'}
Keep comprehensions readable. If the expression needs several statements or side effects, use a regular loop and make the intermediate steps explicit.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Set versus list, tuple, and dictionary
| Type | Duplicates | Order and indexing | Mutability | Typical purpose |
|---|---|---|---|---|
| Set | Not allowed | Unordered; no indexing or slicing | Mutable | Uniqueness, membership, set algebra |
| List | Allowed | Sequence; supports indexing and slicing | Mutable | Ordered collection and repeated values |
| Tuple | Allowed | Sequence; supports indexing and slicing | Immutable | Fixed records or hashable sequences |
| Dictionary | Keys are unique | Key-based access; stores insertion order | Mutable | Mapping keys to values |
Convert a list to a set when uniqueness matters and sequence order does not. If you must preserve the first-seen order while removing duplicates, a set alone is not the right output structure; use a separate “seen” set while building a list.
values = [3, 1, 3, 2, 1]
seen = set()
ordered_unique = []
for value in values:
if value not in seen:
seen.add(value)
ordered_unique.append(value)
print(ordered_unique) # [3, 1, 2]
Common mistakes and troubleshooting
Using braces for an empty set
Symptom: methods or type checks behave as if the object were a dictionary. Fix: write empty = set().
Trying to index a set
values = {10, 20, 30}
# values[0] # TypeError: 'set' object is not subscriptable
first_for_display = sorted(values)[0]
Sorting creates a list for deterministic access; it does not make the original set ordered.
Adding an unhashable value
Symptom: TypeError: unhashable type: 'list' (or dictionary/set equivalent). Fix: use an immutable representation such as a tuple or frozenset, provided all nested values are hashable.
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Expecting pop() to remove a known item
Symptom: a different value disappears between runs or environments. Fix: call remove(value) or discard(value) when the target is known.
Changing a set while iterating
Do not add or remove elements from a set during a loop over that same set; Python can raise a runtime error. Iterate over a snapshot such as set(values) or collect changes and apply them afterward.
Confusing equality with identity
Set membership uses value equality and hashing. Two separately created, equal immutable values represent the same set element; object identity is not the criterion.
Practical patterns
Remove duplicates from a list
duplicates = ["a", "b", "a", "c", "b"]
unique = set(duplicates)
print(unique)
This intentionally discards order. Use the ordered pattern shown earlier when order is part of the requirement.
Find common permissions
editor = {"read", "write", "comment"}
viewer = {"read", "comment"}
shared = editor & viewer
missing_for_viewer = editor - viewer
Check whether all required values exist
required = {"id", "email"}
received = {"id", "email", "name"}
if required <= received:
print("All required fields are present")
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Performance and reliability considerations
Sets are designed for membership and algebra operations, but the official documentation cited for this guide does not provide a universal numeric benchmark. Actual timing depends on Python version, data shape, hashing cost, and workload. Measure your own application if performance is a requirement rather than assuming a fixed speedup.
Best Value
- Store only hashable values and ensure custom objects implement consistent hashing and equality.
- Use
sorted(my_set)at output boundaries when reproducible text, JSON preparation, or tests require stable ordering. - Do not serialize a set directly as JSON; convert it to a list and choose whether to sort it first.
- For immutable composite membership, use
frozensetand document that callers cannot mutate it.
Or skip the browser setup
If your Python workflow also needs rendered screenshots of documentation, dashboards, or result pages, ScreenshotNeo provides a website screenshot API and MCP server. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing status.
One request is enough:
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://python.org"},
timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
See the ScreenshotNeo documentation for all options, including PNG, JPEG, WebP, PDF, full-page capture, CSS selectors, custom JavaScript, device presets, cookies, headers, caching, asynchronous jobs, signed webhooks, bulk capture, and usage reporting. An MCP server exposes take_screenshot, get_page_info, and capture_pdf to Claude, Cursor, and other MCP clients.
The Free plan includes 1,000 screenshots each month without a card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.
Frequently Asked Questions
Can a set contain another set?
No. A mutable set is unhashable, so it cannot be an element of another set. Use a frozenset when a nested set-like value is required.
How do I get a deterministic representation of a set?
Use sorted(my_set) to create an ordered list before displaying, testing, or serializing the values.
What does symmetric difference return?
It returns values present in exactly one of the two sets, using the ^ operator or symmetric_difference() method.
When should I use a tuple instead of a frozenset?
Use a tuple when sequence order and positional meaning matter; use a frozenset when membership and uniqueness matter and order does not.
Recommended Free Tools
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

