Python sets are unordered, mutable collections designed for fast membership testing and mathematical set operations. They automatically eliminate duplicates and support efficient union, intersection, difference, and symmetric difference computations.
- Constructing Sets
1.1 Mutable Sets
Use curly braces {} or the set() constructor. Empty braces {} create a dictionary—not a set—so always use set() for empty sets.
items_a = {42, 17, 89, 17, 42} # Duplicates removed → {42, 17, 89}
items_b = set('python') # Iterates over string → {'p', 'y', 't', 'h', 'o', 'n'}
empty_set = set() # Correct way to initialize empty set
empty_dict = {} # This is a dict, not a set
print(type(empty_set), type(empty_dict)) # <class 'set'> <class 'dict'>
Key properties:
- Elements are unique and immutable (e.g., numbers, strings, tuples).
- No indexing or slicing—sets are inherently unordered.
1.2 Immutable Sets (frozenset)
frozenset objects are hashable and can be used as dictionary keys or elements of other sets. They lack mutation methods like add() or update().
locked = frozenset(['x', 'y', 'z'])
print(locked) # frozenset({'x', 'y', 'z'})
# locked.add('w') # AttributeError: 'frozenset' object has no attribute 'add'
- Core Set Operations
2.1 Adding Elements
add() inserts a single immutable element. Repeated calls with existing values have no effect.
data = {100, 200}
data.add(300)
data.add(100) # No change
print(data) # {100, 200, 300}
update() accepts any iterable and merges its elements. It does not accept scalars directly.
data = {100, 200}
data.update([300, 400]) # From list
data.update('ab') # From string → adds 'a', 'b'
print(data) # {100, 200, 300, 400, 'a', 'b'}
2.2 Removing Elements
remove(x): RaisesKeyErrorifxis absent.discard(x): Silently ignores missing elmeents.pop(): Removes and returns an arbitrary element; raisesKeyErroron empty sets.clear(): Empties the set in-place.
values = {5, 15, 25}
values.remove(15) # OK
# values.remove(99) # KeyError
values.discard(99) # Safe — no error
popped = values.pop() # e.g., 5 or 25
values.clear() # Now empty
2.3 Membership Testing
Use in and not in for O(1) average-case lookups.
inventory = {'hammer', 'screwdriver', 'wrench'}
print('screwdriver' in inventory) # True
print('drill' not in inventory) # True
2.4 Union (Combining Sets)
union() produces a new set containing all unique elements from all inputs. Original sets remain unchanged.
group_a = {'Alice', 'Bob', 'Charlie'}
group_b = {'Bob', 'Diana', 'Eve'}
all_members = group_a.union(group_b) # {'Alice', 'Bob', 'Charlie', 'Diana', 'Eve'}
also_all = set.union(group_a, group_b) # Equivalent
multiple_union = group_a.union(group_b, {'Frank'}) # Supports >2 args
2.5 Subset and Disjoint Checks
issubset(other): ReturnsTrueif all element of the calling set exist inother.issuperset(other): Opposite ofissubset.isdisjoint(other): ReturnsTrueif no element appears in both sets.
small = {1, 2}
large = {1, 2, 3, 4, 5}
print(small.issubset(large)) # True
print(large.issuperset(small)) # True
print({1, 2}.isdisjoint({3, 4})) # True
print({1, 2}.isdisjoint({2, 3})) # False
2.6 Shallow Copying
copy() creates a new set with the same elements—changes to the copy do not affect the original.
original = {10, 20, 30}
duplicate = original.copy()
duplicate.add(40)
print(original) # {10, 20, 30}
print(duplicate) # {10, 20, 30, 40}
2.7 Difference (Set Subtraction)
difference() returns elements present only in the left operand. difference_update() modifies the caller in-place.
left = {1, 2, 3, 4}
right = {3, 4, 5, 6}
only_left = left.difference(right) # {1, 2}
left.difference_update(right) # left becomes {1, 2}
2.8 Intersection (Common Elements)
intersection() yields elements common to all operands. intersection_update() applies the result to the left operand.
set_x = {1, 2, 3, 4}
set_y = {2, 3, 5, 6}
set_z = {2, 3, 7}
common = set_x.intersection(set_y, set_z) # {2, 3}
set_x.intersection_update(set_y) # set_x becomes {2, 3}
2.9 Symmetric Difference (Exclusive OR)
symmetric_difference() returns elements in either set but not both. symmetric_difference_update() modifies the left operand.
set_p = {1, 2, 3}
set_q = {3, 4, 5}
exclusive = set_p.symmetric_difference(set_q) # {1, 2, 4, 5}
set_p.symmetric_difference_update(set_q) # set_p becomes {1, 2, 4, 5}