Skip to Content
Sets

Sets

Sets are unordered, unindexed collections of unique elements. Items cannot be changed after creation, but you can add and remove items.

Creating Sets

You can build a set in several ways:

ApproachExampleUse when
Literal {}nums = {2, 4, 6}You know the elements (at least one; see empty below)
Empty setseq = set()Placeholder; not {} - that is an empty dict
set()set() → empty setSame as literal for empty
set(iterable)set([2, 4, 6]){2, 4, 6}From list, tuple, range, string (chars), etc.
nums = {2, 4, 6, 8, 10} built = set([2, 4, 6, 8]) # from list built = set((2, 4, 6, 8)) # from tuple - note double parentheses empty = set() # use set(); {} creates a dict

Length: Use len(s) to get the number of elements.

Type: type(nums)<class 'set'>.

Truthiness: An empty set is falsy; a non-empty set is truthy. Use if s: for “at least one element” and if not s: for “empty.”

Set Methods

MethodShortcutDescription
add(x)Add element x
update(*iterables)|=Add all elements from one or more iterables
remove(x)Remove x; raises KeyError if missing
discard(x)Remove x if present; no error if missing
pop()Remove and return an arbitrary element; raises if empty
clear()Remove all elements
union(other, ...)|All elements from all sets
intersection(other, ...)&Elements in all sets
intersection_update(...)&=Keep only elements in all sets
difference(other, ...)-Elements in this set but not in others
difference_update(...)-=Remove elements that appear in others
symmetric_difference(other)^Elements in exactly one set; takes one other (chain for 3+)
symmetric_difference_update(other)^=Replace with symmetric difference; takes one other (chain for 3+)
isdisjoint(other)True if no elements in common; takes one other
issubset(other)<= / <True if every element of this set is in other; < = proper subset
issuperset(other)>= / >True if every element of other is in this set; > = proper superset
copy()Return a shallow copy

Operator vs method: |, &, -, ^ work only between sets. union(), intersection(), difference() accept multiple iterables; symmetric_difference() takes one other (chain for 3+).

Set Properties

  • Unordered - elements have no fixed position; iteration order can change between runs.
  • Unindexed - no s[i] or slicing; use loops or membership tests instead.
  • Unique - duplicate values are dropped; each value appears at most once.
  • Unchangeable items - elements must be hashable; you cannot mutate an element in place, but you can remove and add new ones.

Boolean–int equivalence: True and 1 are treated as the same value; so are False and 0. Only one of each pair is kept.

s = {2, 4, True, 1, 6} # {True, 2, 4, 6} - 1 removed s = {2, 4, False, 0, 6} # {False, 2, 4, 6} - 0 removed

Mixed types: Sets can hold strings, numbers, booleans, tuples, and other hashable types in the same set.

Access Set Items

No indexing. Use a loop or membership tests.

nums = {2, 4, 6, 8, 10} for x in nums: print(x) # order varies 4 in nums # True 12 not in nums # True

Reverse Sets

Sets have no reverse() method. Why: Reversing implies a fixed order (first → last). Sets are unordered, so there is nothing to reverse.

To iterate in descending order, sort first to impose an order, then reverse:

nums = {2, 4, 6, 8} for x in reversed(sorted(nums)): # 8, 6, 4, 2 - descending; order is deterministic print(x)

Add Set Items

add(x) - add a single element.

nums = {2, 4, 6, 8} nums.add(10) print(nums) # {2, 4, 6, 8, 10}

update(*iterables) - add all elements from one or more iterables (sets, lists, tuples, dicts - dict adds keys). Modifies in place; does not return a new set. Duplicates are excluded.

nums = {2, 4, 6} nums.update({8, 10}) # from set nums.update([12, 14]) # from list nums.update((16, 18)) # from tuple nums.update({20, 22}, [24], {26: "x", 28: "y"}) # dict adds keys print(nums) # {2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28}

Remove Set Items

MethodBehavior
remove(x)Remove x; raises KeyError if x not in set
discard(x)Remove x if present; no error if missing
pop()Remove and return an arbitrary element; raises if empty
clear()Remove all elements; leaves an empty set
del sDelete the variable; name is undefined; access raises NameError
nums = {2, 4, 6, 8, 10} nums.remove(6) # {2, 4, 8, 10}; KeyError if 6 not present nums.discard(8) # {2, 4, 10}; no error if 8 not present x = nums.pop() # removes one element; which one is undefined nums.clear() # set()

pop() and order: Sets are unordered; you cannot predict which element pop() removes.

Loop Sets

Iterate directly over elements. Order is not guaranteed.

nums = {2, 4, 6, 8} for x in nums: print(x) # 2, 4, 6, 8 - order may vary

Set Comprehension

Build a set from an iterable (or another set) with an expression and optional filter. Syntax: {expr for x in iterable} or {expr for x in iterable if condition}. Duplicates are dropped automatically.

# All even numbers from a range evens = {x for x in range(10) if x % 2 == 0} # {0, 2, 4, 6, 8} # Unique lengths of strings words = ["hi", "ok", "foo", "bar"] lengths = {len(w) for w in words} # {2, 3} # From a list, keep only positives vals = [2, -4, 6, -8, 10] pos = {v for v in vals if v > 0} # {2, 6, 10}

Like list comprehensions, the expression can be more complex; the result is always a set, so order is not preserved and duplicates are removed.

Sort Sets

Sets have no sort() method. Why: Sets are unordered; they have no index or position. There is no “first” or “last” element to define a sort order.

To get sorted output, convert to a list or tuple and sort. Use the key parameter for a custom order (e.g. sorted(s, key=fn)).

nums = {10, 4, 8, 2, 6} sorted(nums) # [2, 4, 6, 8, 10] - returns a list tuple(sorted(nums)) # (2, 4, 6, 8, 10) - sorted tuple sorted(nums, key=lambda x: -x) # [10, 8, 6, 4, 2] - descending

Join Sets

Union

All elements from all sets. Use union() or |. union() accepts multiple iterables (including lists, tuples); | only works between sets. Duplicates are excluded.

a = {2, 4, 6} b = {4, 6, 8, 10} c = {8, 10, 12} a.union(b) # {2, 4, 6, 8, 10} a.union(b, c) # {2, 4, 6, 8, 10, 12} - 3+ iterables a.union(b, c, [14, 16]) # iterables can be sets, lists, tuples, etc. a | b | c # {2, 4, 6, 8, 10, 12} - operator chains

update() - like union() but modifies in place and returns None. Accepts multiple iterables.

a = {2, 4, 6} a.update({8, 10}, [12, 14]) print(a) # {2, 4, 6, 8, 10, 12, 14}

Intersection

Elements present in all sets. Use intersection() or &. Both accept multiple iterables.

a = {2, 4, 6, 8} b = {4, 6, 8, 10} c = {4, 6, 12} a.intersection(b) # {4, 6, 8} a.intersection(b, c) # {4, 6} - elements in all three a & b & c # {4, 6} - operator chains

Note: True/1 and False/0 are treated as duplicates in intersection (see Set Properties).

intersection_update() - keep only elements in all sets; modifies in place. Accepts multiple iterables.

a = {2, 4, 6, 8} b = {4, 6, 8, 10} c = {4, 6} a.intersection_update(b, c) print(a) # {4, 6}

Difference

Elements in the first set but not in the others. Use difference() or -. Both accept multiple iterables.

a = {2, 4, 6, 8, 10} b = {4, 6} c = {8, 10} a.difference(b) # {2, 8, 10} - remove b's elements a.difference(b, c) # {2} - remove elements in b or c a - b - c # {2} - operator chains (left-associative)

difference_update() - remove elements that appear in others; modifies in place. Accepts multiple iterables.

a = {2, 4, 6, 8, 10} b = {4, 6} c = {8} a.difference_update(b, c) print(a) # {2, 10}

Symmetric Difference

Elements in exactly one set (not in both). Use symmetric_difference() or ^. The method takes one other; for 3+ sets, chain or use the operator.

a = {2, 4, 6} b = {4, 6, 8} c = {6, 8, 10} a.symmetric_difference(b) # {2, 8} - one other a.symmetric_difference(b).symmetric_difference(c) # chain for 3+ a ^ b ^ c # {2, 6, 10} - operator chains

symmetric_difference_update() - replace set with symmetric difference; modifies in place. Takes one other; chain for 3+.

a = {2, 4, 6, 8} b = {4, 6, 8, 10} a.symmetric_difference_update(b) print(a) # {2, 10} a = {2, 4, 6} a.symmetric_difference_update({4, 6, 8}) a.symmetric_difference_update({6, 8, 10}) # chain for 3+ print(a) # {2, 6, 10}

Compare Sets

These methods take one other argument. For 3+ sets, chain with and or combine sets first.

isdisjoint(other) - True if no elements in common.

a = {2, 4, 6} b = {4, 6, 8} c = {8, 10, 12} a.isdisjoint(b) # False - 4, 6 in common a.isdisjoint(c) # True - no overlap # 3+ sets: a.isdisjoint(b | c) or a.isdisjoint(b) and a.isdisjoint(c)

issubset(other) - True if every element of this set is in other. Use <= or < (proper subset). No method for proper subset; use a < b or a.issubset(b) and a != b.

a = {2, 4, 6} b = {2, 4, 6, 8} a.issubset(b) # True a <= b # True a < b # True - proper subset (a ≠ b); no dedicated method a < {2, 4, 6} # False - not proper # 3+ sets: a <= b and a <= c (subset of all); a <= b | c (subset of union)

issuperset(other) - True if every element of other is in this set. Use >= or > (proper superset). No method for proper superset; use a > b or a.issuperset(b) and a != b.

a = {2, 4, 6, 8} b = {4, 6} a.issuperset(b) # True a >= b # True a > b # True - proper superset; no dedicated method # 3+ sets: a >= b and a >= c (superset of all); a >= b | c (contains union of b, c)

Frozenset

frozenset is an immutable set. Elements cannot be added or removed.

Creating: Use frozenset() with any iterable.

nums = frozenset({2, 4, 6, 8}) print(type(nums)) # <class 'frozenset'>

Frozenset methods: Immutable means no add or remove. Frozensets support all non-mutating set operations.

MethodShortcutDescription
copy()Return a shallow copy
difference(other, ...)-Return a frozenset with elements not in others
intersection(other, ...)&Return a frozenset with elements in all sets
isdisjoint(other)Return True if no elements in common
issubset(other)<= / <Return True if every element of this set is in other
issuperset(other)>= / >Return True if every element of other is in this set
symmetric_difference(other)^Return a frozenset with elements in exactly one set
union(other, ...)|Return a frozenset with all elements from all sets
a = frozenset({2, 4, 6}) b = frozenset({4, 6, 8}) c = frozenset({6, 8, 10}) a.copy() # frozenset({2, 4, 6}) a - b # frozenset({2}); a.difference(b, c) # frozenset({2}) a & b # frozenset({4, 6}); a.intersection(b, c) # frozenset({6}) frozenset({2, 4}).isdisjoint({6, 8}) # True; a.isdisjoint(b) # False frozenset({2, 4}).issubset({2, 4, 6}) # True; a <= b # False frozenset({2, 4, 6, 8}).issuperset({4, 6}) # True; a >= b # False a ^ b # frozenset({2, 8}); a.symmetric_difference(b) a | b # frozenset({2, 4, 6, 8}); a.union(b, c) # frozenset({2, 4, 6, 8, 10})

Use case: Use frozenset when you need a hashable set (e.g., as a dict key or set element).

Set vs Other Collections

Python offers several built-in types for grouping values. Picking the right one depends on order, mutability, duplicates, and hashability.

TypeOrdered?Mutable?Duplicates?Hashable?Typical use
setNoYesNoNoUnique items; fast membership; set math
frozensetNoNoNoYesHashable set (dict key, set of sets)
listYesYesYesNoOrdered sequence you change
tupleYesNoYesYes (if elements are)Fixed sequence; dict keys; return values
dictYes (ins.)Yes (vals)No (keys)Keys onlyKey–value mapping

When to use a set: You need unique values, fast membership (x in s), or set operations (union, intersection, difference). Use a list when order or duplicates matter. Use a tuple when the sequence is fixed or must be hashable. Use a frozenset when the set itself must be hashable (e.g. inside another set or as a dict key).

Common use cases:

  • Deduplication: Turn a list (or any iterable) into unique values: unique = set([2, 4, 2, 6, 4, 8]){2, 4, 6, 8}. Order is lost; use list(dict.fromkeys(seq)) if you need to preserve order while deduplicating.
  • Membership testing: Sets give O(1) average lookup. Use a set when you repeatedly check x in collection and do not care about order.
  • Set algebra: Union, intersection, difference, and symmetric difference model real-world sets (e.g. which users are in both groups, which tags are in one list but not another).

Tricky Behaviors

Creating - Empty set

{} is an empty dict, not a set. Use set() for an empty set. There is no literal for an empty set because curly braces are shared with dicts.

Assignment is not copy

b = a makes b refer to the same set as a. Changes via a (e.g. a.add(4)) affect b. Use b = a.copy() or b = set(a) when you need an independent set.

Elements must be hashable

Lists and dicts cannot be set elements (they are mutable and unhashable). Use tuples or frozensets if you need compound values.

Boolean and int overlap

True/1 and False/0 count as the same value in a set. {1, True} has length 1; {0, False} has length 1.

update(dict) adds keys only

Passing a dict to update() adds only its keys, not key–value pairs. s.update({2: "a", 4: "b"}) adds 2 and 4 to s.

remove vs discard

remove(x) raises KeyError when x is missing. discard(x) does nothing in that case. Prefer discard() when the item might not be present.

pop() is arbitrary

Sets are unordered; pop() removes and returns some element, but which one is undefined. Do not rely on a specific element being removed.

sorted() returns a list

sorted(s) gives a list, not a set. Use set(sorted(s)) or tuple(sorted(s)) if you need a set or tuple of sorted values.

union() vs update()

union() returns a new set; update() modifies the set in place and returns None. Do not assign the result of update() and expect a new set.

Frozenset - Immutable

You cannot add or remove elements after creation. There is no add, remove, discard, or update on a frozenset.

Interview Questions

How do you create an empty set? Why not {}?

Use set(). The literal {} creates an empty dict, because curly braces are used for both sets and dicts. Python has no distinct syntax for an empty set.

How do you remove duplicates from a list? What happens to order?

Use set(lst) to get unique values. Order is not preserved. To keep insertion order while deduplicating, use list(dict.fromkeys(lst)) (Python 3.7+ dicts are ordered).

When does shallow vs deep copy matter for sets?

Same as dicts: shallow copy shares nested mutable values. Sets typically hold hashable (immutable) elements, so shallow copy is usually sufficient. Use copy.deepcopy() if you have nested mutables.

Why can’t you use a list as a set element or dict key?

Sets and dicts use hash tables for O(1) lookup. Keys and set elements must be hashable. Lists are mutable and unhashable; use tuples or frozensets instead.

What is the time complexity of set membership (in)?

O(1) average - hash table lookup.

add() vs update() - when to use each?

add(x) adds a single element. update(*iterables) adds all elements from one or more iterables (sets, lists, tuples, dict keys). Use add() for one item; use update() to merge many at once.

remove() vs discard() - when to use each?

remove(x) raises KeyError if x not in set. discard(x) does nothing if missing. Use discard() when absence is acceptable.

When would you use a set comprehension instead of a list comprehension?

When you need a set as the result: unique values, no order, or you plan to do membership tests or set operations. Use {x for x in it} instead of [x for x in it] when duplicates are irrelevant or you want them removed.

Why don’t sets have sort() or reverse()?

Sets are unordered; they have no index or position. There is no “first” or “last” element. To get sorted output, use sorted(s) or tuple(sorted(s)).

union() vs | - can you use iterables with both?

union() accepts multiple iterables (lists, tuples, etc.). | works only between sets. Use union() when merging with non‑sets.

isdisjoint, issubset, issuperset - do they accept multiple sets?

No - each takes one other argument. For 3+ sets, chain with and or combine: a.isdisjoint(b | c) or a <= b and a <= c.

When would you use a frozenset instead of a set?

Use a frozenset when the set must be hashable: as a dict key, as an element of another set, or in any context that requires an immutable value. Use a set when you need to add or remove elements.

When should you choose a set over a list?

Choose a set when you need unique values, fast membership (x in s), or set operations (union, intersection, difference). Choose a list when order or duplicates matter, or when you need indexing.

Last updated on