Skip to main content

How to Remove Elements from a List Using del, pop() and remove() in Python

Python provides three distinct built-in ways to delete elements from a list: the del statement, the pop() method, and the remove() method. Each one targets elements differently, returns different results, and raises different errors when something goes wrong.

This guide explains how each method works, when to use one over the others, how to handle errors safely, and how to avoid common mistakes that lead to bugs in real-world code.

Using del for Index-Based Deletion

The del statement removes an element at a specific index without returning it. It is a statement, not a method, so it does not use parentheses:

nums = [10, 20, 30, 40]
del nums[1]
print(nums)

Output:

[10, 30, 40]

Deleting slices with del

One of the unique strengths of del is its ability to remove multiple elements at once using slice notation:

nums = [10, 20, 30, 40, 50]

# Remove elements at indices 1 and 2
del nums[1:3]
print(nums)

Output:

[10, 40, 50]
nums = [10, 20, 30, 40, 50, 60]

# Remove every other element (indices 0, 2, 4)
del nums[::2]
print(nums)

Output:

[20, 40, 60]

You can also use del to delete the entire list variable:

nums = [10, 20, 30]
del nums
# print(nums) # NameError: name 'nums' is not defined
caution

After del nums, the variable itself is removed from scope. This is different from clearing a list with nums.clear(), which empties the list but keeps the variable.

Using pop() to Retrieve and Remove

The pop() method removes an element by index and returns the removed value. This makes it the right choice when you need to use the deleted element after removal:

nums = [10, 20, 30]

last = nums.pop() # No argument removes the last element
print(last)
print(nums)

Output:

30
[10, 20]
first = nums.pop(0)     # Remove element at index 0
print(first)
print(nums)

Output:

10
[20]

Stack and queue operations with pop()

pop() is the standard tool for implementing stack and queue patterns in Python:

# Stack (LIFO - Last In, First Out)
stack = [1, 2, 3]
stack.append(4)
top = stack.pop()
print(f"Popped from stack: {top}")
print(f"Stack: {stack}")

Output:

Popped from stack: 4
Stack: [1, 2, 3]
# Queue (FIFO - First In, First Out)
queue = [1, 2, 3]
first = queue.pop(0)
print(f"Popped from queue: {first}")
print(f"Queue: {queue}")

Output:

Popped from queue: 1
Queue: [2, 3]
tip

Using pop(0) on a regular list has O(n) time complexity because every remaining element must shift one position to the left. For performance-critical queue operations, use collections.deque instead, which provides O(1) pops from both ends:

from collections import deque

queue = deque([1, 2, 3])
first = queue.popleft() # O(1) operation
print(first)

Output:

1

Using remove() for Value-Based Deletion

The remove() method searches for a value and deletes its first occurrence. Unlike del and pop(), it does not require you to know the index:

fruits = ["apple", "banana", "apple", "cherry"]
fruits.remove("apple")
print(fruits)

Output:

['banana', 'apple', 'cherry']

Notice that only the first "apple" was removed. The second one at what was originally index 2 remains in the list.

Removing all occurrences of a value

A common mistake is assuming remove() deletes every instance of the value. It does not. If you need to remove all occurrences, you have two main options.

Option 1: A while loop with remove()

nums = [1, 2, 1, 3, 1]
while 1 in nums:
nums.remove(1)
print(nums)

Output:

[2, 3]

This approach works but has O(n^2) time complexity because both the in check and remove() scan the list on every iteration.

nums = [1, 2, 1, 3, 1]
nums = [x for x in nums if x != 1]
print(nums)

Output:

[2, 3]

The list comprehension runs in O(n) time and is the preferred approach for removing all occurrences, especially in larger lists.

Error Handling

Each method raises a different exception when it fails, and understanding these differences is important for writing robust code.

del and pop() raise IndexError

nums = [10, 20, 30]

# del with an out-of-range index
del nums[10]

Output:

IndexError: list assignment index out of range
nums = [10, 20, 30]

# pop() with an out-of-range index
nums.pop(10)

Output:

IndexError: pop index out of range

remove() raises ValueError

nums = [10, 20, 30]

nums.remove(999)

Output:

ValueError: list.remove(x): x not in list

Writing safe deletion helpers

To avoid crashes from unexpected missing elements, wrap deletion calls with error handling:

# Safe pop with a fallback default value
def safe_pop(lst, index=-1, default=None):
try:
return lst.pop(index)
except IndexError:
return default

nums = [10, 20, 30]
result = safe_pop(nums, 10, default="Not found")
print(result)
print(nums)

Output:

Not found
[10, 20, 30]
# Safe remove using a membership check
nums = [1, 2, 3]
value_to_remove = 5

if value_to_remove in nums:
nums.remove(value_to_remove)
else:
print(f"{value_to_remove} not found in list")

Output:

5 not found in list
info

The if value in list check before remove() does traverse the list once for the check and potentially once more for the removal. For simple scripts this is perfectly fine, but if you are removing many values from a very large list, consider using a set for lookups or rebuilding the list with a comprehension.

Common Mistake: Modifying a List While Iterating Over It

One of the most frequent bugs when removing elements from a list is modifying the list inside a for loop that is iterating over it:

nums = [1, 2, 3, 4, 5, 6]

# Wrong: modifying the list during iteration skips elements
for n in nums:
if n % 2 == 0:
nums.remove(n)

print(nums)

Output:

[1, 3, 5]

This appears to work here, but the behavior is unreliable. When you remove an element, the indices shift and the iterator can skip the next element. Consider a more problematic case:

nums = [2, 4, 6, 8]

# Wrong: attempts to remove all even numbers
for n in nums:
if n % 2 == 0:
nums.remove(n)

print(nums)

Output:

[4, 8]

Two elements survive because the loop skips over them after each removal shifts the list.

The correct approach is to build a new list with a comprehension or iterate over a copy:

# Correct: list comprehension (recommended)
nums = [2, 4, 6, 8]
nums = [n for n in nums if n % 2 != 0]
print(nums)

Output:

[]
# Correct: iterate over a copy of the list
nums = [2, 4, 6, 8]
for n in nums[:]: # nums[:] creates a shallow copy
if n % 2 == 0:
nums.remove(n)

print(nums)

Output:

[]
warning

Never remove elements from a list while iterating over it directly. Either use a list comprehension to create a filtered list, or iterate over a copy using nums[:] or list(nums).

Quick Comparison

Featuredel list[i]pop(i)remove(x)
Targets byIndex or sliceIndexValue
Returns the removed valueNoYesNo
Removes multiple elementsYes (via slicing)NoNo
Error on failureIndexErrorIndexErrorValueError
Best forBulk deletion, index-based removalStack/queue ops, needing the valueDeleting by content

When to Use Each Method

  • del: Choose this when you need to remove elements by index and do not need the removed value, or when you want to delete a slice of elements in a single operation.
  • pop(): Choose this when you need to both remove and use the removed value, such as in stack or queue patterns, or when processing items one at a time.
  • remove(): Choose this when you know the value you want to delete but not its position in the list. Remember that it only removes the first occurrence.

For removing all occurrences of a value or removing elements based on a condition, a list comprehension is almost always the most efficient and readable approach.