Python __contains__() 方法

Python __contains__() 语法

__contains__() 是 Python 的一个特殊方法(又称 “魔法方法” 或 “双下划线方法”),它用于定义当使用 in 运算符检查一个元素是否存在于对象中时,其行为是怎样的。

语法:

class MyContainer:
    def __contains__(self, item):
        # 检查 item 是否存在于容器中。必须返回 True 或 False
        return item in self._elements

说明:

__contains__() 方法接收以下 2 个参数。

  • self(必选) :约定俗成的名称,表示实例对象。
  • item(必选) :要检查的元素。

__contains__() 方法必须返回一个布尔值(True 或 False)。如果返回其他类型,Python 会抛出 TypeError 异常。

提示:

  • 如果一个类实现了 __contains__() 方法,那么它的实例就支持使用 in 和 not in 运算符。
  • 如果一个类没有实现 __contains__() 方法,那么 in 运算符会尝试通过遍历对象(即调用 __iter__()__getitem__())来检查元素是否存在,这可能效率较低。因此,对于自定义容器类,如果需要频繁进行成员测试,强烈建议实现 __contains__()。

Python __contains__() 摘要

属于 Python 魔法方法
使用频率
官方文档 查看
相关方法 __iter__()

Python __contains__() 示例

接下来,我们通过几个简单的例子来讲解一下 Python __contains__() 方法是如何使用的。

示例 1:对内置容器类型使用 in 运算符

# 列表
fruits = ['apple', 'banana', 'cherry']
print('banana' in fruits)    # True
print('orange' in fruits)    # False

# 字符串
s = 'lvyenet'
print('lvye' in s)    # True
print('Lvye' in s)    # False

# 字典(检查键)
d = {'name': 'Jack', 'age': 20}
print('name' in d)    # True
print('city' in d)    # False

# 集合
s = {10, 20, 30}
print(10 in s)    # True
print(40 in s)    # False

运行结果如下。

True
False
True
False
True
False
True
False

分析:

内置的容器类型(如列表、字符串、字典、集合等),其内部都实现了 __contains__() 方法(或通过其他方法支持 in 操作)。当我们使用 in 运算符时,Python 会自动调用内部的 __contains__() 来高效地检查元素是否存在。

示例 2:自定义容器实现 __contains__()

class Inventory:
    def __init__(self, items):
        self._items = set(items)    # 使用集合作为内部存储,以获得高效的成员测试

    def __contains__(self, item):
        # 检查物品是否在库存中
        return item in self._items

    def add_item(self, item):
        self._items.add(item)

    def __repr__(self):
        return f'Inventory({self._items})'

# 创建库存对象
inventory = Inventory(['铅笔', '尺子', '橡皮'])

# 使用 in 运算符检查
print('尺子' in inventory)    # True
print('胶布' in inventory)    # False

# 添加新物品后再次检查
inventory.add_item('胶布')
print('胶布' in inventory)    # True

运行结果如下。

True
False
True

分析:

在 Inventory 类中,我们手动实现 __contains__() 方法,使得其实例支持 in 运算符。当执行 item in inventory 时,__contains__() 方法被调用,它会检查 item 是否存在于内部的 _items 集合中。

示例 3:没有 __contains__() 但可迭代的类

class MyIterable:
    def __init__(self, data):
        self._data = list(data)

    def __iter__(self):
        # 实现迭代协议
        return iter(self._data)

    # 注意:这里故意不实现 __contains__()

    def __repr__(self):
        return f'MyIterable({self._data})'

iterable = MyIterable([10, 20, 30, 40, 50])

# 使用 in 运算符检查 (会触发 __iter__() 遍历)
print(20 in iterable)
print(50 in iterable)

# 再次检查
print(30 in iterable)

运行结果如下。

True
True
True

分析:

如果一个类没有实现 __contains__() 方法,但它是可迭代的(即实现了 __iter__() 或 __getitem__()),那么 in 运算符会退而求其次,通过迭代对象来检查元素是否存在。不过需要注意的是,这种方式对于大型集合可能会效率非常低下。

示例 4:基于特定规则的 __contains__()

class NumberChecker:
    def __init__(self, min_val, max_val):
        self.min_val = min_val
        self.max_val = max_val

    def __contains__(self, number):
        """
        检查一个数字是否在指定范围内。
        这不依赖于内部存储的元素,而是基于规则。
        """
        return self.min_val <= number <= self.max_val

    def __repr__(self):
        return f'NumberChecker(range=[{self.min_val}, {self.max_val}])'

# 创建检查器实例
checker1 = NumberChecker(10, 20)

# 检查数字
print(5 in checker1)      # False
print(15 in checker1)     # True

# 可以将范围设置为负数或小数
checker2 = NumberChecker(-0.5, 0.5)
print(0.2 in checker2)    # True
print(-1.0 in checker2)   # False

运行结果如下。

False
True
True
False

分析:

__contains__() 方法也可以用于实现基于自定义逻辑的成员测试,而不是简单地检查内部列表或集合。

在这个例子中,NumberChecker 类并没有一个内部的数字集合,而是根据 min_val 和 max_val 这两个属性定义了一个范围。

当对 NumberChecker 实例使用 in 运算符时,__contains__() 方法会执行一个逻辑检查,判断传入的 number 是否在这个预设的范围内。

上一篇: __next__()

下一篇: __eq__()

给站长反馈

绿叶网正在不断完善中,小伙伴们如果发现任何问题,还望多多给站长反馈,谢谢!

邮箱:lvyenet@vip.qq.com

「绿叶网」服务号
绿叶网服务号放大
关注服务号,微信也能看教程。
绿叶网服务号