理解Python中的真值、假值及空值的隐含意义

隐藏的教义:__bool__ 和真理的设计

在Python中,真理并不是简单的真(True)和假(False)二元对立。它是意义的反映。Python会问:“在逻辑的上下文中,这个对象对自身有什么描述?”

为了控制一个对象在布尔上下文中的行为,例如在if语句中,你可以定义__bool__方法。

让我们重新开始。

第一部分:解释器的问题

当Python在布尔上下文中评估一个对象时,如:

if some_object: 
    ...

它执行以下顺序:

  1. 调用 some_object.__bool__(),如果已定义。
  2. 如果未定义,则回退到 some_object.__len__()
    • 如果长度为 0,则视为 False。
    • 否则,视为 True。
  3. 如果两者都未定义,则默认为 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 中,真值并不是固定的。它是由你的设计投射的阴影。你可以选择你的对象如何反射光线,或者光线的缺失。

更多