Linux & Systems

How to find the length of a list in Python (and what len() actually does)

len() is the answer, but knowing why it is O(1), how it differs from counting a generator, and when it lies about nesting saves real debugging time.

The answer is len():

bash
numbers = [4, 8, 15, 16, 23, 42]
print(len(numbers))   # 6

That is the whole answer for the common case. The rest of this is the parts that cause bugs.

Why len() is instant

A Python list stores its own size. len() reads that stored integer, so the call costs the same on a list of six items and a list of six million — it is O(1), not a count.

This is why you should never write a manual counting loop, and why len() inside a loop condition is not the performance problem people sometimes assume it is.

Nested lists: len() counts the outer level only

bash
grid = [[1, 2, 3], [4, 5, 6]]
print(len(grid))              # 2   — two rows, not six values
print(len(grid[0]))           # 3   — items in the first row
print(sum(len(row) for row in grid))   # 6  — total items

This catches people out when a list of records is mistaken for a flat list of fields.

Counting things that are not lists

len() works on anything that knows its own size — strings, tuples, dictionaries, sets, ranges:

bash
len("hello")            # 5
len({"a": 1, "b": 2})   # 2   — keys, not key/value pairs
len({1, 2, 2, 3})       # 3   — a set discards duplicates
len(range(0, 100, 5))   # 20  — computed, not generated

It does not work on a generator, because a generator has no length to report — it produces values on demand and may be infinite:

bash
squares = (x * x for x in range(10))
len(squares)            # TypeError: object of type 'generator' has no len()

sum(1 for _ in squares) # 10 — but this consumes the generator

Note the trap: counting a generator exhausts it. Afterwards it yields nothing, and a second pass silently produces zero results.

Counting with a condition

To count only matching items, do not filter into a new list first — that allocates memory you immediately discard:

bash
readings = [12, -3, 45, 0, -8, 27]

len([r for r in readings if r > 0])     # works, builds a throwaway list
sum(1 for r in readings if r > 0)       # same answer, no allocation

On a handful of items the difference is irrelevant. On a large list or a stream it is the difference between constant and linear memory.

Counting occurrences

For "how many times does this value appear", use count(); for all values at once, use Counter:

bash
colours = ["red", "blue", "red", "green", "red"]

colours.count("red")            # 3

from collections import Counter
Counter(colours)                # Counter({'red': 3, 'blue': 1, 'green': 1})
Counter(colours).most_common(1) # [('red', 3)]

Calling count() in a loop over every distinct value is O(n²); Counter does it in one pass.

Emptiness: do not compare the length

To test whether a list is empty, test the list:

bash
if not items:        # idiomatic
    ...

if len(items) == 0:  # works, but noisier and no faster

Empty containers are falsy in Python, so the first form reads naturally and behaves correctly for lists, strings, dicts and sets alike.

The one real gotcha

len() on a string counts characters, not bytes:

bash
s = "café"
len(s)                  # 4 characters
len(s.encode("utf-8"))  # 5 bytes — é encodes as two

len("👍")               # 1 character
len("👍".encode("utf-8"))  # 4 bytes

If you are validating against a database column limit or a network protocol field, the byte length is usually what matters, and using the character length will let oversized values through.

Rukhsar Malik

Contributor to LearnCybers covering technology and software topics.

Related reading

Newsletter

Get smarter about security

Practical guides, tooling notes and the developments actually worth your attention — delivered when there is something worth saying.

No spam. Unsubscribe in one click.