隐藏的教义:__bool__
和真理的设计
在Python中,真理并不是简单的真(True)和假(False)二元对立。它是意义的反映。Python会问:“在逻辑的上下文中,这个对象对自身有什么描述?”
为了控制一个对象在布尔上下文中的行为,例如在if语句中,你可以定义__bool__
方法。
让我们重新开始。
第一部分:解释器的问题
当Python在布尔上下文中评估一个对象时,如:
if some_object:
...
它执行以下顺序:
- 调用
some_object.__bool__()
,如果已定义。 - 如果未定义,则回退到
some_object.__len__()
:- 如果长度为 0,则视为 False。
- 否则,视为 True。
- 如果两者都未定义,则默认为 True
因此,即使是自定义类也可以定义其自身的真值度量。
第二部分:编写我们自己的真值
让我们构造一个简单的对象:一个智慧的容器。
class Scroll:
def __init__(self, text):
self.text = text
现在,让我们观察它的真实性:
s = Scroll("不要追求真理,只需停止珍视观点。")
if s: print("卷轴在说话。") else: print("卷轴是沉默的。")
这将始终打印“卷轴在说话。”,因为 Scroll 没有__bool__
或__len__
。Python 默认将所有对象视为 True,除非另有说明。
现在,让我们赋予它真实的声音:
class Scroll:
def __init__(self, text):
self.text = text
def __bool__(self):
return bool(self.text.strip())
现在,观察:
Scroll(" ") # 行为类似于 False
Scroll("Peace") # 行为类似于 True
我们已经教会了我们的对象如何表达它的存在。
第三部分:回退到 __len__
如果 __bool__
没有定义,Python 会查找 __len__
。
class WisdomBasket:
def __init__(self):
self.sayings = []
def __len__(self):
return len(self.sayings)
现在:
basket = WisdomBasket()
if basket:
print("有智慧。")
else:
print("篮子是空的。")
当你的对象代表一个集合,并且真实性与其内容相关时,这一点非常有用。
第四部分:将真实性作为设计决策
这有什么重要性?
因为在现实世界的代码中,真实性通常意味着意义。考虑一下:
if response:
...
响应应该意味着什么?
- HTTP请求是否成功?
- 响应体是否包含有用的数据?
- 状态码是否为200?
你决定__bool__
应该传达什么。
在设计API、内部库或用户定义的类时,清晰的真值定义可以减少样板代码,使意图显而易见。
第5部分:关于模糊性的警告
真值应该是明确且直观的。
如果你的对象代表一个配置、请求或资源,考虑“真值”意味着什么。避免那些使逻辑变得模糊的聪明做法:
if config:
# 这意味着什么?
最好进行文档记录,或者在语义不明确的情况下完全避免使用真值。
结束循环
大师没有说:“空列表是 False。”
他说:“不是 false。只是空。”
在 Python 中,真值并不是固定的。它是由你的设计投射的阴影。你可以选择你的对象如何反射光线,或者光线的缺失。