__bool__ 返回 false 但 if obj: 仍进入,是因为 __bool__ 未正确定义(如无 return 或返回非 bool 类型),导致 python 回退到 __len__ 或默认 true;必须显式 return true/false。

为什么 __bool__ 返回 False 但 if obj: 还是进去了?
Python 中真值测试优先调用 __bool__,但前提是它被正确定义且返回布尔值。常见错误是:函数体里没写 return,或返回了非 bool 类型(比如整数 0 或字符串 "")。Python 会静默忽略这类返回,转而 fallback 到 __len__;如果 __len__ 也不存在,就默认为 True。
实操建议:
-
__bool__必须显式return True或return False,不能只写return或return 0 - 若同时定义了
__len__,确保__bool__存在且返回bool,否则__len__会被误用 - 调试时可加
print验证是否真的进了__bool__:def __bool__(self): print("__bool__ called") return len(self.items) > 0
什么时候该用 __bool__ 而不是靠 __len__ 自动推导?
当“空”不等于“长度为 0”时,必须显式实现 __bool__。典型场景如异步任务对象、数据库查询结果集、带缓存状态的容器——它们可能有内容但尚未加载,或长度不可知(__len__ 抛异常或耗时),但你明确知道当前是否“可用”或“就绪”。
实操建议:
- 若类逻辑上存在“未初始化”“失败态”“待决态”,这些状态应由
__bool__明确表达,而非依赖长度 - 避免在
__bool__中做重操作(如网络请求、磁盘读取),真值测试应轻量且无副作用 - 如果
__len__可能抛TypeError(如某些生成器包装类),务必提供__bool__,否则if obj:会直接报错
__bool__ 和 __nonzero__ 是什么关系?
__nonzero__ 是 Python 2 的旧方法名,在 Python 3 中已完全废弃。如果你在旧代码里看到它,必须改成 __bool__;否则在 Python 3 下不会被调用,真值测试将退回到 __len__ 或默认 True。
实操建议:
- 新项目一律只写
__bool__,不要兼容 Python 2 - 迁移老代码时,删掉
__nonzero__,重命名并确保返回值类型正确 - 用
python -m py_compile或静态检查工具(如mypy)可提前发现未定义__bool__导致的隐性 fallback 行为
测试 __bool__ 是否生效的最简验证方式
别只写 print(obj),那不触发真值测试。真正有效的是用 bool() 构造器或条件语句直接测。
实操建议:
- 最小验证组合:
obj = MyContainer() print(bool(obj)) # 必须输出 True/False if obj: print("truthy") else: print("falsy") - 用
assert写单元测试:assert bool(MyContainer([1, 2])) is True assert bool(MyContainer([])) is False
- 注意:
not obj也会触发__bool__,但它是bool(obj)的逻辑反,别把它当独立路径来测
真值测试的逻辑链很短,但一旦中间环节(比如 <strong>bool</strong> 返回了 int)出问题,就会悄无声息地跳到下一层,这种 fallback 很难 debug。最稳妥的做法,是在定义 <strong>bool</strong> 后立刻加一行 assert isinstance(self.<strong>bool</strong>(), bool) 做运行时校验——虽然生产环境通常不加,但开发阶段值得这么做。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











