set.remove()
Remove an element from the set — raise KeyError if it is not there. The strict counterpart to set.discard().
Common call
seen.remove(item)
Returns
None — the set loses one element (or raises)
Replaces
discard() when the caller is CERTAIN the element is present
Watch out
missing element raises KeyError — use discard() for silent removal
set.remove(elemelem — The element to remove. Must be present — missing raises KeyError. Must be hashable — lists, dicts, sets raise TypeError.type: hashable · required)
→ None
Demo
Live evaluation
Try:
Inputs
setsetstarting set (comma-separated)
elemAnyelement to remove
Output
{'a', 'b', 'c'}.remove('b')
None
The demo shows the SET STATE after removing. Python actually returns None; the meaningful effect is mutation. remove() raises KeyError when the element is missing — exactly the behavior discard() was designed to avoid. Pick remove when absence is a bug worth catching; pick discard when absence is expected.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| elem | hashable | yes | The element to remove. Must be present — missing raises KeyError. Must be hashable — lists, dicts, sets raise TypeError. |
Return value
None — Returns None — the useful effect is mutation. The demo shows the set state after removing (or the error when the element is missing).
Common patterns
Assertion-style removal
Use remove when the element MUST be there. A missing one signals a bug and the KeyError is the right response.
active.remove(session_id) # raises if the session was never active
Guarded remove
When you want to handle the missing case explicitly rather than silently.
try: s.remove(x) except KeyError: log.warning("expected %s in set", x)
Prefer discard for "maybe present"
The whole point of choosing set.remove over set.discard is the exception on missing.
if x is required_to_be_present: s.remove(x) else: s.discard(x)
Examples
1. Element present
s = {"a", "b", "c"}
s.remove("b")
s
Returns
{"a", "c"}2. Missing raises
s = {"a", "b"}
s.remove("z")
Returns
KeyError: 'z'3. From empty raises
set().remove("x")
Returns
KeyError: 'x'4. Returns None
{"a", "b"}.remove("a")
Returns
None5. Last element ok
s = {"only"}
s.remove("only")
s
Returns
set()Pitfalls
1. KeyError on missing — pick discard() if that is not what you want
The whole difference between remove and discard is this one behavior. If your code cannot guarantee the element is present, discard is the safer default.
Blows up
s = {"a", "b"} s.remove("z")
KeyError: 'z'
Silent
s.discard("z")
no error, no change
2. The `s = s.remove(...)` bug
remove() returns None. Assigning its result back sets your variable to None — the same class of bug as add, sort, and discard.
Now s is None
s = {"a", "b"} s = s.remove("a") print(s)
None
Just remove
s.remove("a") # mutate, keep name
{"b"}
3. Unhashable elements raise TypeError, not KeyError
remove needs to hash the element to look it up. Passing a list or dict raises BEFORE the missing-check would fire — a different error class from what you might expect.
Wrong error type
s = {1, 2, 3} s.remove([1])
TypeError: unhashable type: 'list'
Hashable form
s.remove(1)
no error
4. Removing while iterating
Mutating a set you are iterating over raises RuntimeError. Iterate a snapshot instead.
Runtime error
for x in s: if predicate(x): s.remove(x)
RuntimeError: set changed size during iteration
Iterate a copy
for x in list(s): if predicate(x): s.remove(x)
safe
When to use
Use it
- Elements you KNOW should be present — a missing one is a bug
- Assertion-style pruning where the exception is the point
- Wrapping in try/except to detect and log unexpected absences
Reach for something else
- "Remove if present" workflows → set.discard is idempotent
- You want to remove ANY element (not a specific one) → set.pop
- Removing many at once → set.difference_update or `-=`
- Iterating and removing from the same set → iterate a snapshot
Notes
Complexity
O(1) amortized — hash table lookup and removal
Return
None; the set is mutated in place
CPython impl
Objects/setobject.c :: set_remove
Memory
In-place; no allocation
Thread-safe
Not safe under concurrent mutation of the same set
FAQ
remove raises KeyError when the element is missing; discard silently does nothing. Pick remove when absence signals a bug; pick discard when absence is expected and cheap to ignore.
History
2.3
set type added; remove has been the strict-delete method from the start.