__hash__、__eq__ 和 "in" 运算符
我看到很多关于 __eq__
和 __hash__
以及它们之间关系的问题,虽然我遇到了一个让我感到困惑的现象,但我想先澄清一下。
我有一个字典 team
,里面的键是很多 player
的实例。这个 player
类比较复杂,但它包含了 __hash__
和 __eq__
这两个方法。我还想提到的是,player
类里有一些属性是字典,我觉得这可能是问题的根源。
无论如何,我的代码如下:
if player in team.keys():
name, height = team[player]
奇怪的是,当我检查 player in team
时,它返回 True
(这意味着条件成立,所以下面的代码会执行),但第二行却抛出了 KeyError
。我搞不懂为什么 in
能正常工作,而键却没有正确地被哈希。
有什么建议吗?
编辑:
player
类包含以下魔法方法。cnfg_dict
是一个字典,里面有几个用户指定的配置,其中 required_attrs
用来区分不同的 player
实例(据说是这样...)。
def __init__(self, cnfg_dict):
self.config_dict = cnfg_dict
self.required_attrs = ['attr1', 'attr2']
def __eq__(self, other):
return all([self.config_dict[attr] == other.config_dict[attr] for attr in self.required_attrs])
def __ne__(self, other):
required_attrs = ['dt', 'author']
return any([self.config_dict[attr] != other.config_dict[attr] for attr in required_attrs])
def __repr__(self):
return str([str(a)+'='+str(self.config_dict[a]) for a in self.required_attrs])
def __hash__(self):
return hash(repr(self))
1 个回答
0
我对你说的“相等的对象会有相同的 repr 函数”这个观点不太放心。特别是当你处理数字的时候,这样做是有风险的。这里有个例子:
[in] >>> a = {'name': 'Zelaznik', 'height': 6}
[in] >>> b = {'name': 'Zelaznik', 'height': 6.0}
[in] >>> a == b
[out] >>> True
[in] >>> repr(a['height']) == repr(b['height'])
[out] >>> False
我猜你可能在处理一个玩家的身高时遇到了这个问题。
这里有个简单的方法来解决 hash 函数的问题:
def __hash__(self):
dct = self.confg_dict
keys = self.required_attr
return hash(tuple([dct[k] for k in keys]))
看起来你在使用一个叫“Player”的类,这个类有一组固定的键。这样的话,你可以通过使用 namedtuple 来简化你的工作。
from collections import namedtuple
Player = namedtuple('Player', ('name', 'height', 'opt_attr1', 'opt_attr2'))
Player.__new__.__defaults__ = (None, None) #Sets default values for last two arguments.
https://docs.python.org/2/library/collections.html#collections.namedtuple