结论:len() 要求 len 必须返回非负整数,否则立即报错;它不转换类型、不兜底,仅直接调用并校验返回值类型与符号。

直接说结论:只要在类里定义 __len__ 方法并返回一个非负整数,len() 就能正常调用;但返回值类型或符号不对会立刻报错。
为什么 len() 调用会失败?
Python 的 len() 函数底层只做一件事:尝试调用对象的 __len__ 方法,然后强制要求返回值是 int 且 ≥ 0。它不接受 float、None、负数,也不做任何转换或兜底。
常见错误现象:
-
TypeError: 'float' object cannot be interpreted as an integer(返回了3.0或len(self.data) * 1.0) -
TypeError: __len__() should return an int(返回了True、"5"、None) -
ValueError: __len__() should return >= 0(返回了-1,哪怕逻辑上想表示“未初始化”)
__len__ 必须返回 int,不能是其他“看起来像数字”的类型
即使你的数据结构天然支持长度计算(比如内部有 list 或 dict),也得显式转成 int。Python 不会帮你隐式转换。
立即学习“Python免费学习笔记(深入)”;
快速生成专业的 Python 脚本和应用代码。一键创建完整项目结构,支持CLI、API、爬虫、Bot、Django等多种项目类型,包含完整的项目结构、配置文件、依赖管理、测试、README和文档。
实操建议:
- 直接返回
len(self._items)这种已知安全的表达式(前提是_items本身支持len) - 避免用
sum(1 for x in self._items)—— 效率低,且万一生成器耗尽后再次调用会返回 0 - 不要写
return int(len(self._items))—— 多余,len()本来就会返回int - 如果长度需动态计算(如过滤后计数),确保缓存或加
@property避免重复遍历
示例(正确):
class Bag:
def __init__(self, items):
self._items = list(items)
def __len__(self):
return len(self._items) # ✅ 返回 int什么时候不该实现 __len__?
不是所有类都适合支持 len()。核心判断标准是:这个“长度”是否具备明确、稳定、无副作用的语义。
容易踩的坑:
- 对流式数据(如文件句柄、网络响应体)实现
__len__—— 可能触发读取、阻塞或抛异常 - 对异步迭代器(
async for)返回长度 ——__len__是同步方法,无法await - 让
__len__触发数据库查询 —— 用户调用len(obj)时完全没预料到会有 IO - 返回值随外部状态变化(如另一个线程修改了内部列表)—— 导致
len(obj)多次调用结果不一致,违反直觉
真正关键的不是“能不能写 __len__”,而是“用户调用 len() 时,是否清楚自己在问什么、以及这个答案是否可靠”。很多看似方便的魔术方法,一旦语义模糊,反而会让调试变得更难。

















