假设我有一些Person实体,我想知道一个是否在列表中:
person in people?
我不关心'对象的ID'是什么,只是他们的属性是相同的。所以我把它放在我的基类中:
# value comparison only
def __eq__(self, other):
return (isinstance(other, self.__class__) and self.__dict__ == other.__dict__)
def __ne__(self, other):
return not self.__eq__(other)
但是为了能够在集合中测试相等性,我还需要定义哈希所以......
# sets use __hash__ for equality comparison
def __hash__(self):
return (
self.PersonID,
self.FirstName,
self.LastName,
self.etc_etc...
).__hash__()
问题是我不想列出每个属性,每次属性更改时我都不想修改哈希函数。
这样做可以吗?
# sets use __hash__ for equality comparison
def __hash__(self):
values = tuple(self.__dict__.values())
return hash(values)
这是否理智,而不是 toooo 大部分性能损失?在网络应用的情况下。
非常感谢。
答案 0 :(得分:4)
字典的无序性意味着tuple(self.__dict__.values())
如果dict
碰巧被不同地排序(这可能发生,例如,如果一个人的属性分配在不同的顺序)。
由于您的values
可以播放,您可以尝试使用此选项:
return hash(frozenset(self.__dict__.iteritems()))
或者,请注意__hash__
不需要考虑所有因素,因为当哈希值比较相等时,__eq__
仍将用于验证相等性。因此,你可以侥幸逃脱
return hash(self.PersonID)
假设PersonID
在各实例之间相对独特。
答案 1 :(得分:1)
如果您已经__dict__
使用__eq__
相等,那么对__dict__
__hash__
使用values
会有点愚蠢。但是,return hash(tuple(sorted(self.__dict__.viewitems())))
给出了一个任意排序的列表,其中不包含哪个值对应哪个属性的信息,因此代码实际上不起作用。相反,你可以尝试
return hash(frozenset(self.__dict__.viewitems()))
或
{{1}}
这两个都会删除排序问题并保留属性名称信息。
答案 2 :(得分:0)
感谢您提出的好问题。你正在做我想做的事。在阅读完这些答案之后,我做了类似但有一些差异的事情。
def __str__(self):
return "{}({})".format(type(self).__name__, ", ".join(["{}={}".format(k, self.__dict__[k]) for k in sorted(self.__dict__)]))
def __eq__(self, other):
return isinstance(other, type(self)) and self.__dict__ == other.__dict__
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash(tuple(self.__dict__[k] for k in sorted(self.__dict__)))
我包含了额外信用的字符串方法,因为我在考虑哈希方法后重新编写了这个方法。
我在另一个答案中发现self.__eq__
不应该直接调用,所以我使用==
代替。
此哈希使用按键排序的类属性值的元组。这将确保元组中的顺序是一致的。如果您对值进行排序而不是大小写,则交换的两个属性将具有相同的哈希值。