ZetCode

Python __bool__ 方法

最后修改于 2025 年 4 月 8 日

本综合指南探讨了 Python 的 __bool__ 方法,该特殊方法定义了对象的真值。我们将介绍基本用法、真值规则、实际示例和常见模式。

基本定义

调用 __bool__ 方法来实现真值测试和内置的 bool() 函数。它应该返回 TrueFalse

当未定义 __bool__ 时,Python 会回退到 __len__。如果两者都未定义,则默认情况下对象被认为是 True。此方法对于控制流语句至关重要。

基本 __bool__ 实现

这是一个简单的示例,展示了如何实现 __bool__ 来控制对象的真值。该方法必须返回一个布尔值。

basic_bool.py
class Account:
    def __init__(self, balance):
        self.balance = balance
    
    def __bool__(self):
        return self.balance > 0

account1 = Account(100)
account2 = Account(-50)

print(bool(account1))  # True
print(bool(account2))  # False

if account1:
    print("Account has funds")

此示例定义了一个 Account 类,如果帐户余额为正,则认为该帐户为真值。 __bool__ 方法封装了此业务逻辑。

当对象在布尔上下文中(如 if 语句或使用 bool() 函数)使用时,会自动调用该方法。

__bool__ 与 __len__ 回退

当未定义 __bool__ 时,Python 使用 __len__ 作为回退。此示例显示了这两种方法如何协同工作。

bool_len.py
class ShoppingCart:
    def __init__(self, items):
        self.items = items
    
    def __len__(self):
        return len(self.items)
    
    def __bool__(self):
        return any(item.price > 0 for item in self.items)

class Item:
    def __init__(self, price):
        self.price = price

cart1 = ShoppingCart([Item(10), Item(20)])
cart2 = ShoppingCart([Item(0), Item(0)])

print(bool(cart1))  # True (__bool__ returns True)
print(bool(cart2))  # False (__bool__ returns False)
print(bool(ShoppingCart([])))  # False (__len__ returns 0)

此示例表明 __bool__ 优先于 __len__。 对于空购物车,当未定义 __bool__ 时,Python 会回退到 __len__

只有当购物车包含至少一个价格为正的商品时,才认为该购物车为真值,这展示了自定义的真值逻辑。

数据验证中的真值

__bool__ 可用于实现验证逻辑,使对象可在布尔上下文中使用,以检查其有效性。

validation.py
class UserProfile:
    def __init__(self, name, email):
        self.name = name
        self.email = email
        self._validate()
    
    def _validate(self):
        self.is_valid = (
            isinstance(self.name, str) and 
            '@' in self.email
        )
    
    def __bool__(self):
        return self.is_valid

valid_user = UserProfile("Alice", "alice@example.com")
invalid_user = UserProfile(123, "bobexample.com")

print(bool(valid_user))    # True
print(bool(invalid_user))  # False

if not invalid_user:
    print("Profile is invalid")

此示例使用 __bool__ 来公开验证状态。 该方法返回初始化期间设置的内部 is_valid 标志。

当您希望对象通过布尔测试以自然的方式自我报告其有效性时,此模式非常有用。

自定义容器真值

对于类似容器的对象,__bool__ 可以根据容器状态提供有意义的真值,类似于内置容器。

container.py
class Playlist:
    def __init__(self, songs):
        self.songs = list(songs)
    
    def __bool__(self):
        return len(self.songs) > 0 and any(
            song.duration > 0 for song in self.songs
        )
    
    def __len__(self):
        return len(self.songs)

class Song:
    def __init__(self, duration):
        self.duration = duration

empty_playlist = Playlist([])
playlist_with_silent_tracks = Playlist([Song(0), Song(0)])
valid_playlist = Playlist([Song(180), Song(240)])

print(bool(empty_playlist))               # False
print(bool(playlist_with_silent_tracks))  # False
print(bool(valid_playlist))               # True

只有当此 Playlist 类包含持续时间为正的歌曲时,才认为它是真值。它将长度检查与内容验证相结合。

该实现遵循 Python 的原则,即空容器为假值,但使用关于什么构成“有效”播放列表的特定于域的逻辑对其进行扩展。

有状态对象中的 __bool__

对于有状态对象,__bool__ 可以反映当前状态,使状态检查更直观和 Pythonic。

stateful.py
class TrafficLight:
    def __init__(self):
        self._state = 'red'
    
    def change(self):
        if self._state == 'red':
            self._state = 'green'
        elif self._state == 'green':
            self._state = 'yellow'
        else:
            self._state = 'red'
    
    def __bool__(self):
        return self._state == 'green'

light = TrafficLight()
print(bool(light))  # False

light.change()
print(bool(light))  # True

light.change()
print(bool(light))  # False

此交通灯实现使用 __bool__ 来指示灯是否为绿色。布尔值随灯的状态而变化。

当检查对象状态时,此模式使代码更具可读性,因为 if light: 清楚地表达了检查绿色状态的意图。

最佳实践

资料来源

作者

我叫 Jan Bodnar,是一位充满热情的程序员,拥有丰富的编程经验。我自 2007 年以来一直在撰写编程文章。 迄今为止,我已经撰写了 1,400 多篇文章和 8 本电子书。 我拥有超过十年的编程教学经验。

列出所有 Python 教程