The __len__() AttributeError occurs when Python code calls len() on an object that does not implement the __len__ method. To resolve this, verify that your custom classes define a def __len__(self) function returning an integer, or ensure you are not calling len() on unsupported types like functions or None.
Understanding the Error Mechanism
In Python, the built-in functionlen() is a convenient wrapper around the special method __len__. When you pass an object to len(), the Python interpreter attempts to call the __len__ method on that specific object instance. If the class definition for that object lacks this method, or if the method returns a non-integer value, Python raises an AttributeError or TypeError. This design allows developers to create custom objects that behave like standard sequences, such as lists or strings, by implementing specific "dunder" methods.
For example, a list has __len__ defined in its internal structure, allowing len(my_list) to work seamlessly. However, if you create a simple class without defining how it calculates its length, Python has no way of knowing what "length" means for that object. This is distinct from missing attributes; here, the issue is specifically about the absence of the protocol required for length calculation.
Common Scenarios Triggering the Error
The most frequent cause involves user-defined classes where the developer forgets to implement the length protocol. Consider a scenario where you build a custom container class but only define methods for adding items, neglecting to specify how many items exist. Another common mistake occurs when developers try to get the length of a variable that holdsNone or a function object rather than a collection. For instance, calling len(print) will fail because the print function does not have a length. Additionally, subclassing issues can arise if a parent class defines __len__ but the child class overrides it incorrectly or fails to call the parent implementation when necessary.
Fixing Custom Class Implementations
If you are working with a custom class, the solution requires explicitly defining the__len__ method within the class body. This method must accept self as its first argument and return an integer representing the size of the object. Below is a correct implementation pattern for a custom stack-like structure.
class MyStack:
def __init__(self):
self.items = []
def push(self, item):
self.items.append(item)
def __len__(self):
return len(self.items)
stack = MyStack()
stack.push(1)
stack.push(2)
print(len(stack)) # Output: 2
In this example, __len__ delegates to the underlying list's length. It is crucial that the return value is strictly an integer. Returning float or None will result in a TypeError when len() attempts to use the result for iteration or sizing operations.
Debugging Unsupported Types
Sometimes the error stems from usinglen() on a type that simply does not support it. Python documentation lists which types support the sequence protocol. Built-in types like str, list, tuple, dict, and bytes all support len(). However, generators, functions, and instances of classes without __len__ do not.
To diagnose this, check the type of the object before calling len(). You can use the type() function or inspect the class hierarchy. If you encounter a third-party library object that should have a length but doesn't, check the library's documentation. Some older libraries may require accessing a specific attribute (like .count or .size) instead of using the universal len() function. Always ensure the variable you are passing is initialized and not None, as len(None)` always raises an AttributeError.
Best Practices for Length Calculation
When designing classes, consider whether exposing length is part of your public API. If your object represents a collection, implementing __len__ is essential for compatibility with Pythonic idioms like list comprehensions and for` loops. If calculating the length is expensive, you might cache the result in an instance variable and update it whenever the collection changes. This avoids recalculating the size every time len() is called.
Furthermore, remember that __len__ should never raise exceptions for normal states. If the object is in an invalid state, handle that logic separately rather than letting len() crash. This ensures that code checking for emptiness using if not obj: works correctly, as Python uses __bool__ or falls back to __len__ for truth value testing.
Frequently Asked Questions
Why does len() work on lists but not on my custom object?
Lists are built-in types that have the __len__ method implemented in C. Your custom object is a Python class that likely lacks this method definition. You must add def __len__(self): to your class to make it compatible with len().
Can I use len() on a generator object?
No, generator objects do not support len() because they are lazy iterators and their total size is often unknown until consumed. Convert the generator to a list using list(generator) if you need to determine its length, though this consumes memory.
What happens if __len__() returns a negative number?
Python allows __len__ to return negative integers, but this is considered bad practice and may confuse other parts of the ecosystem. Most libraries expect non-negative lengths. It is better to validate your data before returning the count.
How do I check if an object supports len()?
You can use the hasattr(obj, '__len__') function to check for the existence of the method. Alternatively, try calling len(obj) inside a try-except block catching TypeError or AttributeError to handle unsupported types gracefully.
Is there a difference between __len__ and __bool__?
Yes, __len__ returns an integer count, while __bool__ returns a boolean indicating truthiness. Python uses __bool__ first for truth tests, falling back to __len__ if __bool__ is not defined. An object with __len__ returning 0 is considered False in boolean contexts.