set.discard()
Remove an element from the set. Silently does nothing if it is not present — the safe counterpart to set.remove().
Common call
seen.discard(item)
Returns
None — the set may lose an element
Replaces
a manual `if x in s: s.remove(x)` check
Watch out
unlike list.remove or set.remove, missing element is NOT an error
set.discard(elemelem — The element to remove. If not present, discard does nothing. Non-hashable arguments (list, dict, set) still raise TypeError — they cannot be searched for.type: hashable · required)
→ None
Demo
Live evaluation
Try:
Inputs
setsetstarting set (comma-separated)
elemAnyelement to remove
Output
{'a', 'b', 'c'}.discard('b')
None
The demo shows the SET STATE after discarding. Python actually returns None; the meaningful effect is mutation. discard() silently ignores missing elements — that is the whole point of choosing it over remove(). Order shown is not meaningful; Python sets are unordered.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| elem | hashable | yes | The element to remove. If not present, discard does nothing. Non-hashable arguments (list, dict, set) still raise TypeError — they cannot be searched for. |
Return value
None — Returns None — the useful effect is mutation. The demo shows the set state after discarding.
Common patterns
"Remove if present" no-branch
discard is already idempotent — no `if in` needed.
seen.discard(x) # no branch; safe whether x is there or not
Reset a flag
Turning a flag off is a single call, regardless of prior state.
flags.discard("debug")
Prune from a set of listeners
Common in publish/subscribe patterns where the same subscriber may be removed multiple times.
subscribers.discard(callback)
Examples
1. Element present
s = {"a", "b", "c"}
s.discard("b")
s
Returns
{"a", "c"}2. Missing is a no-op
s = {"a", "b"}
s.discard("z")
s
Returns
{"a", "b"} # unchanged, no error3. From empty set
s = set()
s.discard("x")
s
Returns
set() # no error4. Returns None
{"a", "b"}.discard("a")
Returns
NonePitfalls
1. discard vs remove — silence vs KeyError
discard is silent on missing. remove raises KeyError. Reaching for remove when you meant discard causes a crash on the very case discard was designed for.
Blows up
s = {"a", "b"} s.remove("z")
KeyError: 'z'
Silent
s.discard("z")
no error, no change
2. The `s = s.discard(...)` bug
discard() returns None. Assigning its result back sets your variable to None — the same class of bug as add, sort, and extend.
Now s is None
s = {"a", "b"} s = s.discard("a") print(s)
None
Just discard
s.discard("a") # mutate, keep name
{"b"}
3. Silent no-op — you cannot tell if anything happened
discard gives no signal. If you need to know whether the element was actually removed, check membership before calling.
Fake count
count = 0 for x in items: s.discard(x) count += 1
count is len(items), not len(actually_removed)
Check first
count = 0 for x in items: if x in s: s.discard(x) count += 1
count of real removals
4. Unhashable elements still raise TypeError
discard needs to hash the element to look it up. Passing a list or dict raises before the missing-check runs.
Unhashable
s = {1, 2, 3} s.discard([1])
TypeError: unhashable type: 'list'
Hashable
s.discard((1,)) s.discard(1)
no error
When to use
Use it
- Removing an element that may or may not be there — the "idempotent delete" pattern
- Resetting flags in a flag set
- Cleanup where duplicate discards should not cause errors
- Any code where the caller cannot guarantee the element is present
Reach for something else
- You need to know whether the element was actually there → check membership first
- You want an exception on missing → set.remove instead
- You need to remove ANY element (not a specific one) → set.pop
- Removing many at once → set.difference_update or `-=`
Notes
Complexity
O(1) amortized — hash table lookup and removal
Return
None; the set is mutated in place
CPython impl
Objects/setobject.c :: set_discard
Memory
In-place; no allocation
Thread-safe
Not safe under concurrent mutation of the same set
FAQ
discard silently does nothing when the element is missing; remove raises KeyError. Pick discard for "remove if present" workflows and remove for "this element MUST be there — raise if it is not".
History
2.3
set type added; discard has been the safe-delete method from the start.