覆盖__eq__和__hash__以比较两个实例的dict属性

时间:2015-04-16 13:22:00

标签: python compare

我正在努力理解如何根据每个实例拥有的基础dict属性正确比较对象。

由于我要覆盖__eq__,我还需要覆盖__hash__吗?我没有牢牢掌握何时/何地这样做,并且可以真正使用一些帮助。

我在下面创建了一个简单的示例来说明我遇到的最大递归异常。 RegionalCustomerCollection按地理区域组织帐户ID。如果区域及其各自的RegionalCustomerCollectionaccountid,则items()个对象被认为是相等的。基本上,所有from collections import defaultdict class RegionalCustomerCollection(object): def __init__(self): self.region_accountids = defaultdict(set) def get_region_accountid(self, region_name=None): return self.region_accountids.get(region_name, None) def set_region_accountid(self, region_name, accountid): self.region_accountids[region_name].add(accountid) def __eq__(self, other): if (other == self): return True if isinstance(other, RegionalCustomerCollection): return self.region_accountids == other.region_accountids return False def __repr__(self): return ', '.join(["{0}: {1}".format(region, acctids) for region, acctids in self.region_accountids.items()]) 的内容都应该相同。

>>> a = RegionalCustomerCollection()
>>> b = RegionalCustomerCollection()
>>> a.set_region_accountid('northeast',1)
>>> a.set_region_accountid('northeast',2)
>>> a.set_region_accountid('northeast',3)
>>> a.set_region_accountid('southwest',4)
>>> a.set_region_accountid('southwest',5)
>>> b.set_region_accountid('northeast',1)
>>> b.set_region_accountid('northeast',2)
>>> b.set_region_accountid('northeast',3)
>>> b.set_region_accountid('southwest',4)
>>> b.set_region_accountid('southwest',5)

让我们创建两个对象实例并用一些示例数据填充它们:

>>> a == b
... 
RuntimeError: maximum recursion depth exceeded while calling a Python object

现在让我们尝试比较两个实例并生成递归异常:

{{1}}

2 个答案:

答案 0 :(得分:3)

您的对象不应该返回哈希值,因为它是可变的。如果将此对象放入字典或设置中,然后再将其更改,则可能永远无法再找到它。

为了使对象不可删除,您需要执行以下操作:

class MyClass(object):
    __hash__ = None

这将确保对象不可用。

 [in] >>> m = MyClass()
 [in] >>> hash(m)
[out] >>> TypeError: unhashable type 'MyClass'

这是否回答了你的问题?我怀疑不是因为您明确要求哈希功能。

就您收到的RuntimeError而言,由于以下行而导致:

    if self == other:
        return True

这会让你进入无限递归循环。请尝试以下方法:

    if self is other:
        return True

答案 1 :(得分:1)

您不需要覆盖__hash__来比较两个对象(如果您想要自定义哈希,则需要这样做,即在插入集或词典时提高性能)。

此外,你在这里有无限递归:

    def __eq__(self, other):
        if (other == self):
            return True

        if isinstance(other, RegionalCustomerCollection):
            return self.region_accountids == other.region_accountids

        return False 

如果两个对象都是RegionalCustomerCollection类型,那么自==调用__eq__以来,您将无限递归。