【问题标题】:Recommended way to implement __eq__ and __hash__实现 __eq__ 和 __hash__ 的推荐方法
【发布时间】:2017-12-23 04:45:32
【问题描述】:

python documentation 提到,如果您覆盖 __eq__ 并且对象是不可变的,您还应该覆盖 __hash__ 以使该类能够正确地进行哈希处理。

实际上,当我这样做时,我经常会得到类似的代码

class MyClass(object):
    def __init__(self, a, b):
        self.a = a
        self.b = b

    def __eq__(self, other):
        if type(other) is type(self):
            return (self.a == other.a) and (self.b == other.b)
        else:
            return False

    def __hash__(self):
        return hash((self.a, self.b))

这有点重复,很明显有可能在更新另一个时忘记更新。

有没有推荐的方式来一起实现这些方法?

【问题讨论】:

    标签: python equality hashable


    【解决方案1】:

    回答我自己的问题。执行此操作的一种方法似乎是定义一个辅助__members 函数并在定义__hash____eq__ 时使用它。这样就没有重复了:

    class MyClass(object):
        def __init__(self, a, b):
            self.a = a
            self.b = b
    
        def __members(self):
            return (self.a, self.b)
    
        def __eq__(self, other):
            if type(other) is type(self):
                return self.__members() == other.__members()
            else:
                return False
    
        def __hash__(self):
            return hash(self.__members())
    

    【讨论】:

    • 这里存在self.aself.b 更改的风险,这会导致哈希更改(这会破坏各种事情)
    【解决方案2】:

    这相当于单行eq吗?

       def __eq__(self, other):
           return type(other) is type(self) and (self.a == other.a) and (self.b == other.b)
    

    【讨论】:

      【解决方案3】:

      我认为你可以使用用户定义的哈希函数更好。

      class MyClass(object):
      
      def __init__(self, a, b):
          self.a = a
          self.b = b
      
      def __eq__(self, other):
          if type(other) is type(self):
              return (self.a, self.b) == (other.a, other.b)
          else:
              return NotImplemented
      
      def __hash__(self):
          return hash((self.a, self.b))
      

      【讨论】:

      • 这将给出错误的结果,例如MyClass(2, -2) == MyClass(-2, 2) 因为 CPython 中的 hash collision。永远不要使用hash(a) == hash(b) 来决定ab 是否相等。
      • 是的,这是我的错。我修复了代码
      猜你喜欢
      • 2017-03-14
      • 2015-08-01
      • 2011-03-05
      • 1970-01-01
      • 2011-02-23
      • 1970-01-01
      • 1970-01-01
      • 2018-09-13
      • 2020-08-28
      相关资源
      最近更新 更多