412

What is the cost of len() function for Python built-ins? (list/tuple/string/dictionary)

Martin Thoma
  • 124,992
  • 159
  • 614
  • 958
Imran
  • 87,203
  • 23
  • 98
  • 131

5 Answers5

487

It's O(1) (constant time, not depending of actual length of the element - very fast) on every type you've mentioned, plus set and others such as array.array.

kcpr
  • 1,055
  • 1
  • 12
  • 28
Alex Martelli
  • 854,459
  • 170
  • 1,222
  • 1,395
  • 27
    Thanks for the helpful answer! Are there any native types for which this is not the case? – mvanveen Mar 16 '12 at 03:41
  • 2
    interesting that get length runtime is only mentioned for list here - https://wiki.python.org/moin/TimeComplexity [not mentioned for other types] – Chaitanya Bapat May 17 '21 at 00:07
  • But why is it `O(1)?` – Freddy Mcloughlan May 18 '22 at 12:52
  • 2
    len() is a very frequent operation, and making it O(1) is extremely easy from the viewpoint of implementation -- Python just keeps each collection's "number of items" (length) stored and updated as part of the collection data structure. – Alex Martelli May 18 '22 at 17:02
  • I assume its only O(1) because it was already calculated at time of creation and getting len(x) is just accessing that stored value – Kevin Jun 19 '22 at 02:32
163

Calling len() on those data types is O(1) in CPython, the official and most common implementation of the Python language. Here's a link to a table that provides the algorithmic complexity of many different functions in CPython:

TimeComplexity Python Wiki Page

James Thompson
  • 46,512
  • 18
  • 65
  • 82
122

All those objects keep track of their own length. The time to extract the length is small (O(1) in big-O notation) and mostly consists of [rough description, written in Python terms, not C terms]: look up "len" in a dictionary and dispatch it to the built_in len function which will look up the object's __len__ method and call that ... all it has to do is return self.length

Wolf
  • 9,679
  • 7
  • 62
  • 108
John Machin
  • 81,303
  • 11
  • 141
  • 189
93

The below measurements provide evidence that len() is O(1) for oft-used data structures.

A note regarding timeit: When the -s flag is used and two strings are passed to timeit the first string is executed only once and is not timed.

List:

$ python -m timeit -s "l = range(10);" "len(l)"
10000000 loops, best of 3: 0.0677 usec per loop

$ python -m timeit -s "l = range(1000000);" "len(l)"
10000000 loops, best of 3: 0.0688 usec per loop

Tuple:

$ python -m timeit -s "t = (1,)*10;" "len(t)"
10000000 loops, best of 3: 0.0712 usec per loop

$ python -m timeit -s "t = (1,)*1000000;" "len(t)"
10000000 loops, best of 3: 0.0699 usec per loop

String:

$ python -m timeit -s "s = '1'*10;" "len(s)"
10000000 loops, best of 3: 0.0713 usec per loop

$ python -m timeit -s "s = '1'*1000000;" "len(s)"
10000000 loops, best of 3: 0.0686 usec per loop

Dictionary (dictionary-comprehension available in 2.7+):

$ python -mtimeit -s"d = {i:j for i,j in enumerate(range(10))};" "len(d)"
10000000 loops, best of 3: 0.0711 usec per loop

$ python -mtimeit -s"d = {i:j for i,j in enumerate(range(1000000))};" "len(d)"
10000000 loops, best of 3: 0.0727 usec per loop

Array:

$ python -mtimeit -s"import array;a=array.array('i',range(10));" "len(a)"
10000000 loops, best of 3: 0.0682 usec per loop

$ python -mtimeit -s"import array;a=array.array('i',range(1000000));" "len(a)"
10000000 loops, best of 3: 0.0753 usec per loop

Set (set-comprehension available in 2.7+):

$ python -mtimeit -s"s = {i for i in range(10)};" "len(s)"
10000000 loops, best of 3: 0.0754 usec per loop

$ python -mtimeit -s"s = {i for i in range(1000000)};" "len(s)"
10000000 loops, best of 3: 0.0713 usec per loop

Deque:

$ python -mtimeit -s"from collections import deque;d=deque(range(10));" "len(d)"
100000000 loops, best of 3: 0.0163 usec per loop

$ python -mtimeit -s"from collections import deque;d=deque(range(1000000));" "len(d)"
100000000 loops, best of 3: 0.0163 usec per loop
mechanical_meat
  • 163,903
  • 24
  • 228
  • 223
  • 2
    This is not so good of a benchmark even though it shows what we already know. This is because range(10) and range(1000000) is not supposed to be O(1). – Unknown Jul 12 '09 at 05:45
  • 4
    This is by far the best answer. You should just add a conclusion just in case someone doesn't realize the constant time. – santiagobasulto Jan 21 '13 at 13:14
  • 6
    Thanks for the comment. I added a note about the O(1) complexity of `len()`, and also fixed the measurements to properly use the `-s` flag. – mechanical_meat Jan 21 '13 at 17:21
  • It is important to note that saving the length into a variable could save a significant amount of computational time: `python -m timeit -s "l = range(10000);" "len(l); len(l); len(l)"` 223 nsec per loop `python -m timeit -s "l = range(100);" "len(l)"` 66.2 nsec per loop – Radostin Stoyanov Jan 04 '20 at 19:27
45

len is an O(1) because in your RAM, lists are stored as tables (series of contiguous addresses). To know when the table stops the computer needs two things : length and start point. That is why len() is a O(1), the computer stores the value, so it just needs to look it up.

RAHUL KUMAR
  • 1,123
  • 11
  • 9
  • I don't think this is true for python lists. They're linked lists, not arrays, so contiguous addresses are not guaranteed – bluppfisk Jul 05 '23 at 06:34
  • 1
    @bluppfisk You are totally wrong. Here are the python docs https://docs.python.org/3/faq/design.html#how-are-lists-implemented-in-cpython – airled Aug 05 '23 at 09:52