set.remove()

set.remove(elem)
Returns: None · Updated March 15, 2026 · Set Methods
sets methods mutation

The .remove() method removes an element from a set if it is present. If the element is not found, it raises a KeyError. This behavior differs from .discard(), which silently does nothing when the element does not exist. Use .remove() when you want to ensure the element was actually in the set.

Syntax

set.remove(elem)

Parameters

ParameterTypeDescription
elemanyThe element to remove from the set. Must be hashable.

Raises

  • KeyError — if the element is not found in the set

Examples

Basic usage

Remove an element that exists:

fruits = {"apple", "banana", "cherry"}
fruits.remove("banana")
print(fruits)
# output: {'apple', 'cherry'}

Removing raises KeyError if not found

Unlike .discard(), .remove() raises an error if the element does not exist:

numbers = {1, 2, 3}
try:
    numbers.remove(99)
except KeyError:
    print("Element not found!")
# output: Element not found!

This makes .remove() useful when you need to confirm the element was actually present.

Checking before removing

Check if the element exists first if you are unsure:

colors = {"red", "green", "blue"}

if "green" in colors:
    colors.remove("green")
    print("Removed green")
else:
    print("green not in set")
# output: Removed green

Or handle the exception:

tags = {"python", "coding", "tutorial"}

try:
    tags.remove("guide")
except KeyError:
    print("Tag not found")
# output: Tag not found

Comparing remove() vs discard()

The key difference is error behavior:

my_set = {1, 2, 3}

# Using remove() on existing element - works fine
my_set.remove(2)
print(f"After remove(2): {my_set}")
# output: After remove(2): {1, 3}

# Using discard() on existing element - also works
my_set.discard(1)
print(f"After discard(1): {my_set}")
# output: After discard(1): {3}

# Now both are empty - remove() fails, discard() does not
my_set.remove(99)  # KeyError!
my_set.discard(99)  # Silent success

Removing in a loop

Be careful when removing items while iterating:

numbers = {1, 2, 3, 4, 5}

# Copy first to avoid "set changed size during iteration"
for num in list(numbers):
    if num % 2 == 0:
        numbers.remove(num)

print(numbers)
# output: {1, 3, 5}

A safer approach is to use a set comprehension:

numbers = {1, 2, 3, 4, 5}
evens_removed = {n for n in numbers if n % 2 != 0}
print(evens_removed)
# output: {1, 3, 5}

Working with custom objects

The objects must be hashable:

# Strings work fine
words = {"hello", "world"}
words.remove("hello")
print(words)
# output: {'world'}

# Tuples work (they are immutable)
coords = {(0, 0), (1, 1), (2, 2)}
coords.remove((1, 1))
print(coords)
# output: {(0, 0), (2, 2)}

# Lists do not work (unhashable)
try:
    my_list = {[1, 2], [3, 4]}
except TypeError as e:
    print(f"Error: {e}")
# output: Error: unhashable type: 'list'

Use case: task management

Remove completed tasks and confirm they existed:

pending_tasks = {"review PR", "deploy to staging", "write tests"}

def complete_task(task_name):
    try:
        pending_tasks.remove(task_name)
        print(f"Completed: {task_name}")
        return True
    except KeyError:
        print(f"Task not found: {task_name}")
        return False

complete_task("deploy to staging")
complete_task("deploy to staging")
# output: Completed: deploy to staging
# output: Task not found: deploy to staging

Common Patterns

Ensuring an element exists before processing

users = {"alice", "bob", "charlie"}

def assign_role(username):
    if username in users:
        users.remove(username)
        print(f"Removed {username} from pending")
    else:
        print(f"{username} not in pending users")

assign_role("bob")
assign_role("dave")
# output: Removed bob from pending
# output: dave not in pending users

Set difference with confirmation

def remove_items(target, to_remove):
    """Remove all items in to_remove from target."""
    removed_count = 0
    for item in to_remove:
        try:
            target.remove(item)
            removed_count += 1
        except KeyError:
            pass
    return removed_count

available = {1, 2, 3, 4, 5}
requested = [2, 4, 6]
count = remove_items(available, requested)
print(f"Removed {count} items: {available}")
# output: Removed 2 items: {1, 3, 5}

Performance

The .remove() method has:

  • Average case: O(1) time complexity
  • Worst case: O(n) when hash collisions occur

This is the same performance as .discard() — the only difference is the error behavior.

See Also