Python设置"in"运算符:使用相等或身份?

Gen*_*tal 32 python identity equality set operator-keyword

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])
Run Code Online (Sandbox Code Playgroud)

为什么第一行打印为True,但第二行打印为False?既不进入运营商eq?

我使用的是Python 2.6

Ray*_*ger 16

设置__contains__按以下顺序进行检查:

 'Match' if hash(a) == hash(b) and (a is b or a==b) else 'No Match'
Run Code Online (Sandbox Code Playgroud)

相关的C源代码位于Objects/setobject.c :: set_lookkey()和Objects/object.c :: PyObject_RichCompareBool()中.


Dav*_*ver 15

你也需要定义__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])
Run Code Online (Sandbox Code Playgroud)

将按预期工作.

作为一般规则,任何时候你实现__cmp__你应该实现一个__hash__这样的,所有x,y如此x == y,x.__hash__() == y.__hash__().

  • 对,就是这样.集合由散列表支持,因此首先调用`x .__ hash __()`来执行集合成员资格测试(`x in my_set`),检查`my_set`中的任何值是否散列到该值,然后只调用`__eq__ `如果找到匹配的项目. (3认同)
  • @GennadiyRozental是的.`__hash__`实现应该包含与`__eq__`实现相同的对象属性.(把它们全部塞进一个元组和`hash()`那个.) (2认同)

Ben*_*Ben 7

集合和字典通过使用散列作为完全相等性检查的快速近似来获得其速度.如果要重新定义相等性,通常需要重新定义哈希算法以使其保持一致.

默认的哈希函数使用对象的标识,这对于完全相等的快速近似是相当无用的,但至少允许您使用任意类实例作为字典键并检索与其一起存储的值如果您准确传递与键相同的对象.但这意味着如果你重新定义相等并且不重新定义哈希函数,那么你的对象将进入字典/集合而不会抱怨不可用,但仍然不会按照你期望的方式工作.

有关更多详细信息,请参阅官方python文档__hash__.

  • +1用于解释根本原因(默认哈希使用id).使解决方案易于遵循. (3认同)