Python 设置交集和 __eq__

jac*_*wah 1 python set python-2.7

根据此页面, set.intersection 使用该__eq__方法测试元素相等性。任何人都可以向我解释为什么这会失败?

>>> Class Foo(object):
>>>     def __eq__(self, other):
>>>         return True
>>>
>>> set([Foo()]).intersection([Foo()])
set([])
Run Code Online (Sandbox Code Playgroud)

使用 2.7.3。是否有另一种(不太复杂)的方法来做到这一点?

Use*_*ser 5

如果您覆盖,__eq__您也应该始终覆盖__hash__

“如果a == b,那么hash(a) == hash(b)一定是这种情况,否则集合和字典会失败。” 埃里克

__hash__用于从对象中生成整数。这用于将字典的键或集合的元素放入桶中,以便可以更快地找到它们。

如果不覆盖__hash__,默认算法会创建不同的散列整数,尽管对象是相等的。

在你的情况下,我会这样做:

class Foo(object):
    def __eq__(self, other):
        return type(self) == type(other)
    def __hash__(self):
        return 1
Run Code Online (Sandbox Code Playgroud)

因为您的类的所有对象都等于该类的所有其他对象,所以它们必须都在集合中的同一个存储桶 (1) 中。这种方式in也返回True

应该__eq__是什么样子:

  • 如果你只比较 Foo 对象

    def __eq__(self, other):
        return self.number == other.number
    
    Run Code Online (Sandbox Code Playgroud)
  • 如果您还将 Foo 对象与其他对象进行比较:

    def __eq__(self, other):
        return type(self) == type(other) and self.number == other.number
    
    Run Code Online (Sandbox Code Playgroud)
  • 如果你有不同的类和不同的算法,我推荐double-dispatch

    class Foo:
        def __eq__(self, other):
            return hasattr(other, '_equals_foo') and other._equals_foo(self)
        def _equals_foo(self, other):
            return self.number == other.number
        def _equals_bar(self, other):
            return False # Foo never equals Bar
    class Bar:
        def __eq__(self, other):
            return hasattr(other, '_equals_bar') and other._equals_bar(self)
        def _equals_foo(self, other):
            return False # Foo never equals Bar
        def _equals_bar(self, other):
            return True # Bar always equals Bar
    
    Run Code Online (Sandbox Code Playgroud)

    这样双方abina == b决定什么是平等的意思。