设置“in”运算符:使用相等还是身份?
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__
,这样对于所有的 x
和 y
,只要 x == y
,就应该有 x.__hash__() == y.__hash__()
。