ZetCode

Python __contains__ 方法

最后修改于 2025 年 4 月 8 日

这份全面的指南探讨了 Python 的 __contains__ 方法,这是一个实现成员资格测试操作的特殊方法。我们将涵盖基本用法、自定义容器、性能考虑和实践示例。

基本定义

__contains__ 方法实现了成员资格测试运算符(innot in)。如果项目在容器中,它应该返回 True,否则返回 False

主要特征:它接受一个参数(要测试的项目),可以在任何类中定义,并且在使用 in 运算符时自动调用。 它为用户定义的对象启用自定义包含逻辑。

基本 __contains__ 实现

这是一个简单的实现,展示了 __contains__ 如何与 in 运算符一起工作。此示例检查列表中是否存在成员。

basic_contains.py
class MyContainer:
    def __init__(self, items):
        self.items = items
    
    def __contains__(self, item):
        return item in self.items

container = MyContainer([1, 2, 3, 4, 5])
print(3 in container)  # True
print(6 in container)  # False

此示例演示了基本模式。 __contains__ 方法委托给底层列表的包含检查。 in 运算符自动调用此方法。

该方法返回一个布尔值,指示该项目是否存在于容器中。 这个简单的实现反映了 Python 内置的列表行为。

自定义成员资格逻辑

__contains__ 允许实现超出简单值检查的自定义成员资格测试逻辑。 在这里,我们检查偶数。

custom_logic.py
class EvenNumbers:
    def __contains__(self, num):
        return isinstance(num, int) and num % 2 == 0

evens = EvenNumbers()
print(4 in evens)    # True
print(5 in evens)    # False
print("a" in evens)  # False

此实现不存储数字,而是定义了构成数学成员资格的条件。 它检查输入是否为整数且为偶数。

该示例展示了 __contains__ 如何在没有实际存储的情况下实现抽象包含规则。 这种模式对于虚拟容器很有用。

不区分大小写的字符串容器

此示例演示了一个字符串容器,该容器执行不区分大小写的成员资格测试,这对于大小写规范化场景很有用。

case_insensitive.py
class CaseInsensitiveContainer:
    def __init__(self, items):
        self.items = [item.lower() for item in items]
    
    def __contains__(self, item):
        return item.lower() in self.items

fruits = CaseInsensitiveContainer(['Apple', 'Banana', 'Orange'])
print('apple' in fruits)    # True
print('BANANA' in fruits)   # True
print('pear' in fruits)     # False

该容器存储所有项目的小写版本,并在检查之前将搜索词转换为小写。 这确保了大小写不会影响成员资格测试。

当您需要不区分大小写的查找,但又想保留存储项目的原始大小写以供显示时,此模式很有用。

基于范围的包含

此示例实现了一个容器,该容器检查数字是否在其任何存储的范围内,从而演示了复杂的包含逻辑。

range_container.py
class RangeContainer:
    def __init__(self, ranges):
        self.ranges = ranges
    
    def __contains__(self, num):
        return any(start <= num <= end for start, end in self.ranges)

ranges = RangeContainer([(1, 5), (10, 15), (20, 25)])
print(3 in ranges)   # True
print(8 in ranges)   # False
print(22 in ranges)  # True

该容器存储表示范围的元组。 __contains__ 方法使用带有 any() 的生成器表达式检查数字是否在这些范围中的任何一个范围内。

此实现有效地处理多个不连续的范围,而无需存储每个可能的值,从而使其在大型范围内具有内存效率。

使用 __contains__ 进行性能优化

此示例展示了 __contains__ 如何通过使用集合进行 O(1) 查找而不是 O(n) 列表搜索来优化成员资格测试。

optimized_contains.py
class OptimizedContainer:
    def __init__(self, items):
        self.items = list(items)
        self.items_set = set(items)
    
    def __contains__(self, item):
        return item in self.items_set

large_data = OptimizedContainer(range(1000000))
print(999999 in large_data)  # Fast lookup
print(-1 in large_data)      # Fast negative result

该类维护一个列表(用于有序访问)和一个集合(用于快速成员资格测试)。 __contains__ 方法使用该集合进行恒定时间查找。

当您需要有序迭代和频繁的成员资格测试时,此模式很有价值。 内存开销可以通过性能提升来证明。

最佳实践

资料来源

作者

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

列出所有 Python 教程