覆盖 __eq__ 和 __hash__ 以比较两个实例的字典属性
Overriding __eq__ and __hash__ to compare a dict attribute of two instances
我正在努力了解如何根据每个实例拥有的基础 dict 属性正确比较对象。
既然我覆盖了 __eq__
,我还需要覆盖 __hash__
吗?我还没有完全掌握 when/where 这样做,真的需要一些帮助。
我在下面创建了一个简单示例来说明我 运行 遇到的最大递归异常。 RegionalCustomerCollection
按地理区域组织帐户 ID。如果区域及其各自的 accountid
相等,则 RegionalCustomerCollection
对象被认为是相等的。本质上,所有 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
您不需要覆盖 __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__
.
您的对象不应该 return 散列,因为它是可变的。如果你把这个对象放入字典或集合中,然后再更改它,你可能再也找不到它了。
为了使对象不可散列,您需要执行以下操作:
class MyClass(object):
__hash__ = None
这将确保对象不可散列。
[in] >>> m = MyClass()
[in] >>> hash(m)
[out] >>> TypeError: unhashable type 'MyClass'
这是否回答了您的问题?我怀疑不是因为您明确在寻找 hash 函数。
就您收到的 RuntimeError 而言,这是因为以下行:
if self == other:
return True
这会让你进入无限递归循环。请尝试以下操作:
if self is other:
return True
我正在努力了解如何根据每个实例拥有的基础 dict 属性正确比较对象。
既然我覆盖了 __eq__
,我还需要覆盖 __hash__
吗?我还没有完全掌握 when/where 这样做,真的需要一些帮助。
我在下面创建了一个简单示例来说明我 运行 遇到的最大递归异常。 RegionalCustomerCollection
按地理区域组织帐户 ID。如果区域及其各自的 accountid
相等,则 RegionalCustomerCollection
对象被认为是相等的。本质上,所有 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
您不需要覆盖 __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__
.
您的对象不应该 return 散列,因为它是可变的。如果你把这个对象放入字典或集合中,然后再更改它,你可能再也找不到它了。
为了使对象不可散列,您需要执行以下操作:
class MyClass(object):
__hash__ = None
这将确保对象不可散列。
[in] >>> m = MyClass()
[in] >>> hash(m)
[out] >>> TypeError: unhashable type 'MyClass'
这是否回答了您的问题?我怀疑不是因为您明确在寻找 hash 函数。
就您收到的 RuntimeError 而言,这是因为以下行:
if self == other:
return True
这会让你进入无限递归循环。请尝试以下操作:
if self is other:
return True