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().
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. |
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.
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
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
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
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
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: 8Implementing 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
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
Practice constant-time sizing, custom __len__() implementations, and deep length counting in our 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 ColabRun 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!
CPython stores the length directly in the object's C struct header (ob_size), reading the stored size instantly without traversing elements.
len(dict) returns the number of distinct keys in the dictionary, equivalent to counting key-value mapping pairs.
No. Python enforces that __len__() must return an integer ≥ 0. Returning negative values raises ValueError; floats raise TypeError.
Generators produce items lazily on demand and do not know their total size in advance without consuming and exhausting the stream.
Author & Instructor at plus2net
I write and maintain practical tutorials on Python, PHP, SQL, JavaScript, HTML, jQuery, and web development at plus2net. The tutorials focus on clear explanations, working examples, and code that readers can test and adapt while learning.