len() behaves similarly at the language level for both built-in types and custom classes — it looks for a special method called __len__() — but there are important implementation differences.
1. Built-in types: optimized, implemented in C
For built-in objects like list, str, tuple, dict, etc., length is usually:
-
Stored internally as metadata
-
Implemented in C for speed
-
Retrieved in O(1) time
Example:
Pythona = [1, 2, 3]
print(len(a)) # 3
Internally, Python does not iterate through the list each time. The list object already stores its size.
2. Custom classes: you provide __len__()
For your own classes, len(obj) calls:
Pythonobj.__len__()
Example:
Pythonclass MyCollection:
def __init__(self, items):
self.items = items
def __len__(self):
return len(self.items)
c = MyCollection([10, 20, 30])
print(len(c)) # 3
Equivalent behavior:
Pythonprint(c.__len__())
3. If __len__() is missing
Python raises a TypeError.
Pythonclass A:
pass
a = A()
print(len(a))
Output:
TypeError: object of type 'A' has no len()
4. Rules for __len__()
Your __len__() method must return:
-
an integer
-
≥ 0
Bad examples:
Pythonclass Bad:
def __len__(self):
return -1
len(Bad())
Output:
ValueError: __len__() should return >= 0
Or:
Pythonclass Bad:
def __len__(self):
return "five"
Output:
TypeError
5. Relationship with truthiness
If __bool__() is absent, Python uses __len__():
Pythonclass Box:
def __len__(self):
return 0
b = Box()
print(bool(b)) # False
Rule:
__bool__() → preferred
otherwise __len__()
otherwise True
6. Important internal difference: special method lookup
For special methods like __len__, Python does not always use normal instance attribute lookup.
This fails:
Pythonclass A:
pass
a = A()
a.__len__ = lambda: 5
len(a) # Error
Because Python looks up __len__ on the class, not the instance.
This works:
Pythonclass A:
def __len__(self):
return 5
a = A()
print(len(a)) # 5
Summary
| Aspect | Built-in Types | Custom Classes |
|---|---|---|
| Where length logic lives | C implementation | Your __len__() |
| Performance | Usually O(1) | Depends on implementation |
| Need to define length? | Already defined | Must implement __len__() |
| Missing length behavior | Rare | TypeError |
| Truthiness fallback | Uses internal length | Uses your __len__() |
The key takeaway: len(x) always tries the object's length protocol (__len__), but built-in types have highly optimized internal implementations while custom classes must explicitly provide that behavior.
All Questions From This Chapter « Previously
