设置“in”运算符:使用相等还是身份?

40 投票
5 回答
10788 浏览
提问于 2025-04-17 12:04
class A(object):
    def __cmp__(self):
        print '__cmp__'
        return object.__cmp__(self)

    def __eq__(self, rhs):
        print '__eq__'
        return True
a1 = A()
a2 = A()
print a1 in set([a1])
print a1 in set([a2])

为什么第一行打印出 True,而第二行打印出 False?而且都没有进入 eq 操作符?

我在使用 Python 2.6

5 个回答

8

集合和字典之所以能快速工作,是因为它们使用了一种叫做哈希的技术,这种技术可以快速判断两个东西是否相等。如果你想改变两个对象相等的标准,通常也需要重新定义哈希算法,这样才能保持一致性。

默认的哈希函数是根据对象的身份来判断的,这种方法在快速判断相等性方面并不太有效。不过,它至少允许你把任意类的实例作为字典的键,并且如果你用完全相同的对象作为键,就能取回存储在里面的值。但如果你改变了相等的标准,却重新定义哈希函数,那么你的对象虽然可以放进字典或集合里,也不会报错说它们不能被哈希,但它们的行为可能不会如你所期待的那样工作。

想了解更多细节,可以查看官方的 Python 文档关于 __hash__ 的内容

24

设置 __contains__ 方法时,检查的顺序如下:

 'Match' if hash(a) == hash(b) and (a is b or a==b) else 'No Match'

相关的C语言源代码在 Objects/setobject.c::set_lookkey() 和 Objects/object.c::PyObject_RichCompareBool() 这两个地方。

17

你还需要定义一下 __hash__。比如说:

class A(object):
    def __hash__(self):
        print '__hash__'
        return 42

    def __cmp__(self, other):
        print '__cmp__'
        return object.__cmp__(self, other)

    def __eq__(self, rhs):
        print '__eq__'
        return True

a1 = A()
a2 = A()
print a1 in set([a1])
print a1 in set([a2])

这样就能正常工作了。

一般来说,每当你实现了 __cmp__ 的时候,你也应该实现一个 __hash__,这样对于所有的 xy,只要 x == y,就应该有 x.__hash__() == y.__hash__()

撰写回答