REW

How Does List Len Work?

Published Aug 29, 2025 4 min read
On this page

Calling len(my_list) on a Python list is an instantaneous, or O(1)cap O open paren 1 close paren 𝑂(1)

, operation because the list object stores its own length as a dedicated attribute. The function does not count the elements; it simply retrieves this pre-computed value, no matter how large the list is. This design decision prioritizes performance and consistency for a fundamental data structure operation.

The internal list structure in CPython

To understand why len() is so fast, we must look at the internal C implementation of Python lists, specifically in CPython, the standard Python interpreter. A Python list is not a traditional linked list but rather a dynamic array, a contiguous block of memory that holds a sequence of pointers to Python objects.

The PyListObject structure in C contains three key components:

  • ob_refcnt: A reference count, which tracks the number of references to the object in the program's memory.
  • ob_item: A pointer to an array of PyObject*, which are the pointers to the actual data elements.
  • allocated: A variable that tracks the total number of items the underlying array can currently hold.

The crucial part for len() is the ob_size attribute, which stores the actual number of elements currently in the list. When you perform an operation that changes the list's size, such as append() or pop(), the interpreter automatically increments or decrements the ob_size counter.

The process of getting the length

When you call len(my_list), the Python interpreter performs these steps:

  1. Look for the __len__ method: The built-in len() function checks if the object passed to it has a special __len__() method.
  2. Call the __len__ method: For lists, Python's C implementation provides a highly optimized __len__() method.
  3. Retrieve ob_size: The C-level function simply retrieves and returns the value of the ob_size attribute from the PyListObject structure.
  4. Return the count: The result is returned to the Python code.

This process is a single lookup and is independent of the number of elements in the list. This is what gives len() its O(1)cap O open paren 1 close paren

𝑂(1)

constant time complexity.

Comparison to alternative methods

The efficiency of len() is most apparent when comparing it to less-optimized methods that beginners might devise. Using a manual loop or an equivalent functional approach has a much higher time complexity, O(n)cap O open paren n close paren

𝑂(𝑛)

, because it requires counting every single element.

Method Time Complexity How it works When to use
len(my_list) O(1)cap O open paren 1 close paren 𝑂(1) (Constant Time) Retrieves a stored attribute value. Always, for maximum efficiency and readability.
sum(1 for _ in my_list) O(n)cap O open paren n close paren 𝑂(𝑛) (Linear Time) Iterates through each element and adds 1 for each item. As a learning exercise to understand iterables; not for production code.
for loop O(n)cap O open paren n close paren 𝑂(𝑛) (Linear Time) Explicitly loops and increments a counter. As a learning exercise; less efficient than len().

Advanced details and considerations

  • Arbitrary objects: The len() function can work on any custom object, as long as you implement the __len__() special (or "dunder") method in the class definition. For example, a Deck class could define __len__ to return the number of cards.

  • Nested lists: len() only counts the top-level elements of a list, even if it contains other lists. A list [[1, 2], [3, 4]] has a length of 2, not 4.

  • List resizing: Although retrieving the length is O(1)cap O open paren 1 close paren

    𝑂(1)

    , other list operations are not. Appending an item is typically fast, but if the underlying dynamic array runs out of allocated space, Python must reallocate a larger block of memory and copy all the old elements to the new location. This resize operation is an O(n)cap O open paren n close paren

    𝑂(𝑛)

    event, but Python's over-allocation strategy (adding extra space so it doesn't have to resize on every append) makes the average case an amortized O(1)cap O open paren 1 close paren

    𝑂(1)

    .

Enjoyed this article? Share it with a friend.