Python len(): Measuring Length, Collection Sizing, and the __len__() Protocol

The len() built-in function returns the number of items in a container, sequence, or mapping.

O(1) Constant Time Efficiency: In CPython, built-in containers (list, str, dict, set, tuple) store their element count directly in the object header, allowing len() to return instantly in O(1) time without counting elements. To iterate with index positions, see enumerate(), or generate index sequences with range().

1. Syntax & Parameter Specifications 🔝

The len() function accepts a single sequence or collection argument:

# Formal syntax of built-in len()
element_count = len(s)
Parameter Type Default Description & Operational Rule
s Sequence or Collection Required An object implementing the __len__() protocol (e.g., string, list, tuple, dict, set, range).
Return int N/A A non-negative integer representing the total count of top-level items.
Errors TypeError / ValueError N/A Raises TypeError if object has no length, or ValueError if __len__() returns negative.

Why len() Operates in O(1) Constant Time

Unlike languages that calculate length by iterating to a null terminator, CPython defines all variable-length objects as PyVarObject structures containing an explicit ob_size integer field in C. When you execute len(my_list), Python reads this memory field directly: zero item traversal, zero performance penalty regardless of whether the collection has 10 items or 10,000,000 items.

2. Measuring Built-in Sequences and Mappings 🔝

len() measures character count in strings, element count in lists/tuples/sets, and key count in dictionaries:

# 1. Measuring length across built-in sequences and mappings
text = "plus2net.com"
numbers = [10, 20, 30, 40, 50]
user_profile = {"id": 101, "name": "Alex", "role": "admin"}
unique_tags = {"python", "tutorial", "coding"}

print("String character count:  ", len(text))
print("List element count:      ", len(numbers))
print("Dictionary keys count:   ", len(user_profile))
print("Set unique member count: ", len(unique_tags))

Terminal Output:

String character count:   12
List element count:       5
Dictionary keys count:    3
Set unique member count:  3

3. Length of Nested & Multi-Dimensional Structures 🔝

len() only evaluates the outermost top-level dimension. It does not recursively count nested children:

# 2. Length of nested and multi-dimensional structures
matrix = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
]

print("Top-level rows count:    ", len(matrix))
print("First row columns count: ", len(matrix[0]))

Terminal Output:

Top-level rows count:     3
First row columns count:  3

4. The __len__() Dunder Protocol & Truthiness Fallback 🔝

When you define custom data models, implementing __len__() allows them to participate in Python's standard collection sizing and boolean truthiness checks:

# 3. Custom classes implementing the __len__() protocol
class TaskQueue:
    def __init__(self):
        self._tasks = []

    def add_task(self, task: str):
        self._tasks.append(task)

    def __len__(self) -> int:
        # Custom length hook called by built-in len()
        return len(self._tasks)

queue = TaskQueue()
queue.add_task("Process Order")
queue.add_task("Send Invoice")

print("Queue length via len(): ", len(queue))
# Objects with __len__() automatically support boolean truthiness testing
print("Queue is not empty:     ", bool(queue))

Terminal Output:

Queue length via len():  2
Queue is not empty:      True

5. Unsized Objects: Generators, Streams & Numbers 🔝

Objects that generate items lazily on demand or atomic numerical primitives do not support len():

# 4. Unsized collections: generators and numbers
# Generators are lazy streams without fixed lengths
gen = (x * 2 for x in range(5))
try:
    len(gen)
except TypeError as err:
    print("Generator error: ", err)

# Integers are not collections
account_id = 987654321
try:
    len(account_id)
except TypeError as err:
    print("Integer error:   ", err)

# Converting integer to string to count digits
print("Digit count:     ", len(str(account_id)))

Terminal Output:

Generator error:  object of type 'generator' has no len()
Integer error:    object of type 'int' has no len()
Digit count:      9

6. Production Recipes 🔝

Counting deep atomic items inside arbitrarily nested heterogeneous data structures:

# 5. Production Recipe: Recursive Deep Element Counter
def deep_length(container) -> int:
    """Recursively counts all atomic items inside nested lists, tuples, and sets."""
    count = 0
    if isinstance(container, (list, tuple, set)):
        for item in container:
            if isinstance(item, (list, tuple, set)):
                count += deep_length(item)
            else:
                count += 1
    elif isinstance(container, dict):
        for val in container.values():
            if isinstance(val, (list, tuple, set, dict)):
                count += deep_length(val)
            else:
                count += 1
    else:
        return 1
    return count

nested_data = [1, [2, 3], [4, [5, 6, [7, 8]]]]
print("Shallow len(): ", len(nested_data))
print("Deep length:   ", deep_length(nested_data))

Terminal Output:

Shallow len():  3
Deep length:    8

Implementing custom collection wrappers with dynamic page-count sizing:

# 6. Production Recipe: Sized Paginated Dataset Wrapper
class PaginatedDataset:
    def __init__(self, records, page_size=10):
        self.records = records
        self.page_size = page_size

    def __len__(self):
        # Total number of complete and partial pages
        return (len(self.records) + self.page_size - 1) // self.page_size

dataset = PaginatedDataset(list(range(45)), page_size=10)
print("Total records:        ", len(dataset.records))
print("Total pages via len():", len(dataset))

Terminal Output:

Total records:         45
Total pages via len(): 5

7. Common Developer Pitfalls & Anti-Patterns 🔝

Writing idiomatic Python avoids redundant length checks when evaluating collection emptiness or loop indexing:

# 7. Common traps: Anti-patterns vs. Idiomatic Python
items = [10, 20, 30]

# ANTI-PATTERN 1: if len(items) > 0:
# IDIOMATIC PYTHON: Rely on truth value testing directly
if items:
    print("Collection contains items (idiomatic).")

# ANTI-PATTERN 2: for i in range(len(items)):
# IDIOMATIC PYTHON: Use enumerate() for index + value
for idx, val in enumerate(items):
    print(f"Index {idx}: {val}")

Terminal Output:

Collection contains items (idiomatic).
Index 0: 10
Index 1: 20
Index 2: 30

8. Interactive Notebook & Practice Exercises 🔝

Practice constant-time sizing, custom __len__() implementations, and deep length counting in our interactive companion Jupyter Notebook:

Interactive Companion Jupyter Notebook

Explore interactive code cells, benchmark O(1) length lookups, test nested containers, and run self-validating assertions.

View on GitHub Run in Google Colab

Self-Verifying Assertion Suite

Run these unit checks directly in Python or your local environment to verify len() mechanics:

# 8. Self-verifying unit test suite for len()
# Test 1: Sequences and mappings length
assert len("hello") == 5
assert len([1, 2, 3, 4]) == 4
assert len({"a": 1, "b": 2}) == 2
assert len(set([10, 10, 20])) == 2

# Test 2: Range length without memory expansion
r = range(0, 1000000, 5)
assert len(r) == 200000

# Test 3: Custom class __len__()
class Container:
    def __len__(self): return 42

assert len(Container()) == 42

# Test 4: Boolean truthiness fallback
class SizedObj:
    def __init__(self, size): self.size = size
    def __len__(self): return self.size

assert bool(SizedObj(5)) is True
assert bool(SizedObj(0)) is False

print("All len() unit assertions successfully verified!")

Terminal Output:

All len() unit assertions successfully verified!

9. Frequently Asked Questions (FAQ) 🔝

Why is len() an O(1) operation?

CPython stores the length directly in the object's C struct header (ob_size), reading the stored size instantly without traversing elements.

What does len() return for dictionaries?

len(dict) returns the number of distinct keys in the dictionary, equivalent to counting key-value mapping pairs.

Can __len__() return a float or negative number?

No. Python enforces that __len__() must return an integer ≥ 0. Returning negative values raises ValueError; floats raise TypeError.

Why can't I call len() on a generator?

Generators produce items lazily on demand and do not know their total size in advance without consuming and exhausting the stream.

Further Reading & Related Tutorials 🔝




Subscribe to our YouTube Channel here



plus2net.com







Python Video Tutorials
Python SQLite Video Tutorials
Python MySQL Video Tutorials
Python Tkinter Video Tutorials
✖
We use cookies to improve your browsing experience. . Learn more
HTML MySQL PHP JavaScript ASP Photoshop Articles Contact us
© 2000-2026 plus2net.com All rights reserved worldwide Privacy Policy Disclaimer