我无法理解 python 中的 __contains__ 方法

Posted

技术标签:

【中文标题】我无法理解 python 中的 __contains__ 方法【英文标题】:I am having trouble understanding the __contains__ method in python 【发布时间】:2016-09-10 02:37:30 【问题描述】:

我已经建立了一个简单的类,叫做 Cell

class Cell:
    def __init__(self, letter):
        self.letter = letter
        if letter == 'A' or letter == 'E' or letter == 'I' or letter == 'O' or letter == 'U' or letter == 'L' or letter == 'N' or letter == 'S' or  letter == 'T' or letter == 'R':
            self.points = 1
        elif letter == 'D' or letter == 'G':
            self.points = 2
        elif letter == 'B' or letter == 'C' or letter == 'M' or letter == 'P':
            self.points = 3
        elif letter == 'F' or letter == 'H' or letter == 'V' or letter == 'W' or letter == 'Y':
            self.points = 4
        elif letter == 'K':
            self.points = 5
        elif letter == 'J' or letter == 'X':
            self.points = 8
        elif letter == 'Q' or letter == 'Z':
            self.points = 10
        else:
            self.points = 0

现在我正在尝试为该类编写一个__contains__ 方法,因此如果我有一个单元格数组,我可以检查数组中是否包含某个字母的单元格

Tiles = []
Tiles.append(Cell("A")
Tiles.append(Cell("B")
Tiles.append(Cell("C")
Tiles.append(Cell("D")

Cell("A") in Tiles 应该返回 True

但是我对如何去做这件事感到困惑,并且在网上或 python 文档中几乎没有找到帮助

【问题讨论】:

【参考方案1】:

我正在尝试为该类编写一个__contains__ 方法

不,你不是。这是你在implementing a container 时要问的问题,而不是被收容的东西。

您不会对如何实现__contains__ 感到困惑——您只需在容器 上实现该功能,在本例中就是列表。您对 contains 的工作原理感兴趣。

您需要实现__eq__(以及__hash____ne__,为了更好的衡量标准)

我认为这是说明性的:

class Cell:
    def __init__(self, thing):
       self.thing = thing
    def __eq__(self, other):
       return other.thing == self.thing

a = [Cell(1)]
print Cell(1) in a

这里有更完整的例子:Elegant ways to support equivalence ("equality") in Python classes

我没有看到关于 list contains 如何准确工作的参考,但参考实现在 line 437 here;基本上它遍历列表并检查提供的项目是否等于列表中的任何项目。

这就是我们通过重载 __eq__ 来重载“==”等式运算符的原因。

当然,这个过程是O(n)(所花费的时间与列表中的项目数量成正比——在最坏的情况下我们必须检查每一个)。字典或集合可以在O(1)“恒定”时间内执行此操作,但这需要将输入作为键进行散列。出于这个原因,通常习惯于在重载相等时重载散列函数,以免出现意外行为。 __ne__ 是 python 的“不等于”运算符。 Overload this too

【讨论】:

别忘了__ne__ 集合也是一个没有值的字典,可以在恒定时间内查找可散列值。 谢谢,这是一个很好的答案。我唯一的问题是,如果我正在实现eqne,为什么我需要实现__hash__ 函数 @JamesNotaro 对于列表,您不需要,但对于任何散列其内容的数据结构(如字典或集合),“容器中的单元格(1)”将是散列单元格(1) ,并检查该哈希值是否在容器中。在这种情况下,即使 Cell(1) 与结构中的某些内容等于,因为它的哈希值不匹配,你会得到它不包含【参考方案2】:

如果s 是一个序列,那么m in s 返回一个bool。现在,当type(s) 类实现__contains__ 方法时,s 也可以是sequence-like

因此obj in Tilesobj 的成员资格无关,而是在Tiles 列表中。

其次,为什么Cell('A') in Tiles在添加一个之前返回False?因为它们是不同的对象。通过实现__eq__ 方法,您可以引入新的语义,说明它们在满足某某时相同。

x = Cell('A')
y = Cell('A')
x is y # False, same as id(x) == id(y)
x == y # don't really know what that means
# now enriching semantics by __eq__
x == y # True/ False

如果要将这些对象用作键,则应实现 __hash__ 函数。但有一些警告。检查文档。

【讨论】:

以上是关于我无法理解 python 中的 __contains__ 方法的主要内容,如果未能解决你的问题,请参考以下文章

请问python描述符property中的self.fget(instance)怎么理解

Python中的内置函数__init__()的理解

无法在 Python 中导入我自己的模块

无法理解在 Python 中传递值和引用

Python __len__()__reversed__()__contains__()

理解 __getitem__ 方法