From the docs:

list.remove(x) Remove the first item from the list whose value is x. It is an error if there is no such item.

Without going into the details of the implementation, the item to remove can be anywhere in the list. A linear scan time is necessary in order to find the item before it can be removed. Once you find the index of the item to remove, you need to shift all the elements down by one index. In any case there's index amount of traversal and size - index amount of shifting involved. Therefore the removal time is equivalent to traversing the entire list: O(n).

You can find the source here: https://hg.python.org/cpython/file/tip/Objects/listobject.c#l2197 (also look for list_ass_slice(..)).


However, a set is different. It uses the hash value of the object being stored to locate it in its buckets. On an average, locating of objects using hash value is almost constant time. Note that it might not always be constant time where there's hash collision and a further search is required. But assuming a good hash function, it usually is.

UPDATE: I must thank Stefan Pochmann for pointing out the mistake.

Answer from UltraInstinct on Stack Overflow
🌐
GeeksforGeeks
geeksforgeeks.org › python › python-remove-rear-element-from-list
Python - Remove rear element from list - GeeksforGeeks
April 6, 2023 - Time complexity: O(1) - The pop() method takes constant time to remove the last element from the list. Auxiliary space: O(1) - No extra space is used in this code. Method #2: Using del list[-1] This is just the alternate method to perform the ...
Discussions

algorithm - Why does Python take O(n) time to remove the first element from a list? - Stack Overflow
The Python wiki page on time complexity says that deleting an item takes O(n) time. The description of the deque class in the documentation of the collections module says that "list objects [...] i... More on stackoverflow.com
🌐 stackoverflow.com
optimization - How does Python remove elements from a list so quickly? - Stack Overflow
I thought that the time needed for creating referenced objects is negligible. But now I've tried to first initialize the whole list with zeroes, and than assign them with 1s. It's considerably faster(about 0.3 sec). Although, still noticeably slower than deletion. It looks like the answer can be more complex than I expected. Not just tricky deletion logic, but also some Python ... More on stackoverflow.com
🌐 stackoverflow.com
Python list - del, insert, no. of assignments and time complexity - Stack Overflow
I'm wondering about how many assignments python makes during an insert on an arbitrary index and how many assignments is being made when deleting the first element del(list[0]). I'm a little bit confused since the time complexity for these 2 operations are O(n), n being the number of elements ... More on stackoverflow.com
🌐 stackoverflow.com
algorithm - How to delete an element in python list, in O(1) time - Stack Overflow
I would like to know if we can delete element at any index, say the last index in O(1) time. More on stackoverflow.com
🌐 stackoverflow.com
November 30, 2019
🌐
Reddit
reddit.com › r/learnpython › why is removing elements from a list so slow, and is there a faster way?
r/learnpython on Reddit: Why is removing elements from a list so slow, and is there a faster way?
April 21, 2024 -

I was trying to write a simple application, which is ao supposed to filter a list of words down to a list of words of a certain length. For that I could either remove the words of the wrong length, or create a new list of words with the correct length.

I had a list of around 58000 words, and wanted to filter out all the 6 letter words, which are around 6900.

with open('words.txt') as f:
    words = f.readlines()
    for i in range(len(words)):
        words[i] = words[i].strip()

length = int(input("Desired word length "))

for i in reversed(words):
    if len(i) != length:
        words.remove(i)

This took 22 seconds.

Another way is to just create a new list with words of the correct length. I did this as follows:

with open('words.txt') as f:
    words = f.readlines()
    for i in range(len(words)):
        words[i] = words[i].strip()

length = int(input("Desired word length "))
clw = []

for i in words:
    if len(i) == length:
        clw.append(i)

This only took 0.03 seconds. How can it be that creating a list of 6900 words takes 0.03 seconds, but removing 51100 words takes 22? It's only 7 times as many words, but takes 700 times as long. And is there a better and faster way to quickly remove list elements?

🌐
LabEx
labex.io › tutorials › python-what-is-the-time-complexity-of-list-append-and-remove-operations-in-python-397728
What is the time complexity of list append and remove operations in Python | LabEx
In this tutorial, we will dive into the time complexity of two fundamental list operations in Python: append and remove. Understanding the time complexity of these operations is crucial for writing efficient Python code and optimizing the performance of your applications.
🌐
Python
wiki.python.org › moin › TimeComplexity
TimeComplexity - Python Wiki
The average case for an average value of k is popping the element the middle of the list, which takes O(n/2) = O(n) operations. [3] = For these operations, the worst case n is the maximum size the container ever achieved, rather than just the current size. For example, if N objects are added ...
🌐
Finxter
blog.finxter.com › home › learn python blog › what is the difference between remove(), pop() and del in lists in python?
What is The Difference Between remove(), pop() and del in Lists in Python? - Be on the Right Side of Change
December 17, 2021 - If you specify an element with ... complexity when removing an element in index i from the list of n elements using del is O(n-i). Case 1: To delete the first element from a list of 10000 elements using del....
🌐
Medium
thinklikeacto.medium.com › time-complexity-of-popping-elements-from-list-in-python-215ad3d9c048
Time complexity of popping elements from list in Python! | by Naresh Thakur | Medium
January 23, 2020 - Consider we have following list. ... By doing a.pop() with no arguments it will remove and return the last element which has O(1) time complexity. Because it just remove the last element and do not need to re-arrange the elements. Python list is implemented as an array of pointers.
Find elsewhere
🌐
Quora
quora.com › Why-is-the-time-complexity-of-deleting-an-item-from-an-array-linear-O-n-and-not-constant
Why is the time complexity of deleting an item from an array linear - O(n) and not constant? - Quora
Answer (1 of 5): An array is a rigid block. “Deleting” something out of it leaves a gap. When an array has gaps in it, this causes huge problems. Indexing is compromised, traversal is no longer easy, space wastage is increased, etc. Therefore, when something gets deleted out of an array, ...
Top answer
1 of 2
7

I decided to turn my set of comments into a proper answer.

First off, let's clarify what's happening when you do:

>>> l = [i for i in range(100000000)]

Here three things are happening:

  1. 100000000 int objects are being created. Creating an object in CPython requires allocating memory and placing content into that memory, and this takes time.
  2. You are running a loop. This affects performances considerably: [i for i in range(...)] is much slower than list(range(...)).
  3. The large list is being created on the fly.

Reading your question, it seems that you are considering only the last point, ignoring the others. Therefore, your timings are inaccurate: creating a large list does not take 3 seconds, it takes a fraction of those 3 seconds.

How large is this fraction is an interesting question, which is difficult to answer using only Python code, but still we can try. Specifically, I'd try with the following statement:

>>> [None] * 100000000

Here CPython does not have to create a large amount of objects (there's only None), does not have to run loops and can allocate the memory for the list once (because it knows the size in advance).

Timings are self-explanatory:

$ python3 -m timeit "list(range(100000000))"
10 loops, best of 3: 2.26 sec per loop
$ python3 -m timeit "[None] * 100000000"
10 loops, best of 3: 375 msec per loop

Now, back to your question: how about item deletion?

$ python3 -m timeit --setup "l = [None] * 100000000" "del l[0]"
10 loops, best of 3: 89 msec per loop
$ python3 -m timeit --setup "l = [None] * 100000000" "del l[100000000 // 4]"
10 loops, best of 3: 66.5 msec per loop
$ python3 -m timeit --setup "l = [None] * 100000000" "del l[100000000 // 2]"
10 loops, best of 3: 45.3 msec per loop

These numbers tell us something important. Note that 2 × 45.3 ≈ 89. Also 66.5 × 4 / 3 ≈ 89.

These numbers are telling exactly what linear complexity is about. If a function has time complexity kn (which is O(n)), it means that if we double the input, we double time; if we increase the input size by 4/3, the time increases by 4/3.

And this is what's happening here. In CPython, our list of 100000000 items is a contiguous memory area containing pointers to Python objects:

l = |ptr0|ptr1|ptr2|...|ptr99999999|

When we run del l[0] we are moving ptr1 from right to left, overwriting ptr0. The same for other elements:

l = |ptr0|ptr1|ptr2|...|ptr99999999|
     ^^^^
         ` item to delete

l = |ptr1|ptr2|...|ptr99999999|

Therefore, when we run del l[0] we have to move 99999998 pointers to the left. This is different from del l[100000000 // 2], which requires moving only half the pointers (the pointers on the first half don't need to be moved). "Moving half the pointers" equals "performing half of the operations" which roughly mean "running in half the time" (this is not always true, but timings say that this is true in this case).

2 of 2
3

I'm not sure why you think it should take 3 seconds to delete a single element.

Your initial time is for 100000000 individual append operations. Each of those takes a fraction of a second; your delete operation takes a similar amount of time.

In any case, as Bartosz points out, O(n) complexity doesn't mean that all operations take the same length of time, it means that the length of time is proportional to the length of the list.

🌐
GeeksforGeeks
geeksforgeeks.org › python › python-front-and-rear-range-deletion-in-a-list
Python | Front and rear range deletion in a list - GeeksforGeeks
July 11, 2025 - Time complexity: O(n), because it takes linear time to delete the elements from the list.
🌐
Quora
quora.com › What-is-the-time-complexity-of-removing-an-element-from-an-unsorted-linked-list
What is the time complexity of removing an element from an unsorted linked list? - Quora
Answer (1 of 2): The time complexity of removing an element from an unsorted linked list depends on which element the algorithm removes. If the algorithm is content to remove any element from the list, then the element at the head of the list could always be chosen. Removing the head element tak...
🌐
Stack Overflow
stackoverflow.com › questions › 49732932 › python-list-del-insert-no-of-assignments-and-time-complexity
Python list - del, insert, no. of assignments and time complexity - Stack Overflow
If I have a list containing 100000 elements and I delete the first, does python need 99999 assignments for the shifts or 100000? ... Do you really care if it's 79999 or 80000? If you want to be accurate, the complexity is actually O(n-i+1), where i is the index you're deleting/inserting. The thing is: Nobody cares. It's too specific. The whole point of time complexity analysis is to find out how fast the algorithm is with large numbers.
🌐
LinkedIn
linkedin.com › all › engineering › computer science
How to Delete an Element from a Python List: 3 Methods
March 4, 2024 - Time complexity: O(n) due to subsequent element shifting. remove(value): Efficient when removing a known value without knowing its index. Time complexity: O(n) due to list traversal. del list[index]: Directly deletes the element at the specified ...
🌐
Stack Overflow
stackoverflow.com › questions › 73710891 › deleting-the-first-element-of-a-python-list-in-time-complexity-o1-without-us
Deleting the first element of a python list in time complexity O(1) , without using predefined list functions - Stack Overflow
Say I have [1,3,5,6]. I want to dequeue the list (make it [3,5,6]), and add a space in the end ([3,5,6,None]), in order to enable enqueue later. I want to do all of this in constant time O(1). ... Sounds like you’re trying to implement a double ended queue. You could make your enqueue/dequeue operations work in O(1) if you use a Python list like a ring buffer (so you wouldn’t be removing elements, you’d instead be changing references/altering where the “beginning” and “end” are.
🌐
Unstop
unstop.com › home › blog › remove item from list in python | 5 ways + code examples
Remove Item From List In Python | 5 Ways + Code Examples
February 3, 2025 - The list becomes ['upskill', 'practice', 'get hired'] after the deletion, which we then print to the console. Complexity: The del keyword approach has a time complexity of O(n) for removing a single element or a slice, as it also requires shifting ...
Top answer
1 of 4
10

As you correctly noticed, the CPython implementation of list.clear is O(n). The code iterates over the elements in order to decrease the reference count of each one, without a way to avoid it. There is no doubt that it is an O(n) operation and, given a large enough list, you can measure the time spent in clear() as function of list size:

import time

for size in 1_000_000, 10_000_000, 100_000_000, 1_000_000_000:
    l = [None] * size
    t0 = time.time()
    l.clear()
    t1 = time.time()
    print(size, t1 - t0)

The output shows linear complexity; on my system with Python 3.7 it prints the following:

1000000 0.0023756027221679688
10000000 0.02452826499938965
100000000 0.23625731468200684
1000000000 2.31496524810791

The time per element is of course tiny because the loop is coded in C and each iteration does very little work. But, as the above measurement shows, even a miniscule per-element factor eventually adds up. Small per-element constant is not the reason to ignore the cost of an operation, or the same would apply to the loop that shifts the list elements in l.insert(0, ...), which is also very efficient - and yet few would claim insertion at the beginning to be O(1). (And clear potentially does more work because a decref will run an arbitrary chain of destructors for an object whose reference count actually reaches zero.)

On a philosophical level, one could argue that costs of memory management should be ignored when assessing complexity because otherwise it would be impossible to analyze anything with certainty, as any operation could trigger a GC. This argument has merit; GC does come occasionally and unpredictably, and its cost can be considered amortized across all allocations. In a similar vein complexity analysis tends to ignore the complexity of malloc because the parameters it depends on (like memory fragmentation) are typically not directly related to allocation size or even to the number of already allocated blocks. However, in case of list.clear there is only one allocated block, no GC is triggered, and the code is still visiting each and every list element. Even with the assumption of O(1) malloc and amortized O(1) GC, list.clear still takes the time proportional to the number of elements in the list.

The article linked from the question is about Python the language and doesn't mention a particular implementation. Python implementations that don't use reference counting, such as Jython or PyPy, are likely to have true O(1) list.clear, and for them the claim from the article would be entirely correct. So, when explaining the Python list on a conceptual level, it is not wrong to say that clearing the list is O(1) - after all, all the object references are in a contiguous array, and you free it only once. This is the point your blog post probably should make, and that is what the linked article is trying to say. Taking the cost of reference counting into account too early might confuse your readers and give them completely wrong ideas about Python's lists (e.g. they could imagine that they are implemented as linked lists).

Finally, at some point one must accept that memory management strategy does change complexity of some operations. For example, destroying a linked list in C++ is O(n) from the perspective of the caller; discarding it in Java or Go would be O(1). And not in the trivial sense of a garbage-collected language just postponing the same work for later - it is quite possible that a moving collector will only traverse reachable objects and will indeed never visit the elements of the discarded linked list. Reference counting makes discarding large containers algorithmically similar to manual collection, and GC can remove that. While CPython's list.clear has to touch every element to avoid a memory leak, it is quite possible that PyPy's garbage collector never needs to do anything of the sort, and thus has a true O(1) list.clear.

2 of 4
4

It's O(1) neglecting memory management. It's not quite right to say it's O(N) accounting for memory management, because accounting for memory management is complicated.

Most of the time, for most purposes, we treat the costs of memory management separately from the costs of the operations that triggered it. Otherwise, just about everything you could possibly do becomes O(who even knows), because almost any operation could trigger a garbage collection pass or an expensive destructor or something. Heck, even in languages like C with "manual" memory management, there's no guarantee that any particular malloc or free call will be fast.

There's an argument to be made that refcounting operations should be treated differently. After all, list.clear explicitly performs a number of Py_XDECREF operations equal to the list's length, and even if no objects are deallocated or finalized as a result, the refcounting itself will necessarily take time proportional to the length of the list.

If you count the Py_XDECREF operations list.clear performs explicitly, but ignore any destructors or other code that might be triggered by the refcounting operations, and you assume PyMem_FREE is constant time, then list.clear is O(N), where N is the original length of the list. If you discount all memory management overhead, including the explicit Py_XDECREF operations, list.clear is O(1). If you count all memory management costs, then the runtime of list.clear cannot be asymptotically bounded by any function of the list's length.