在集合中使用不同的 __hash__ 和 __eq__ 方法

Different __hash__ and __eq__ methods for use in set

我正在尝试为一个问题实施基于集合的解决方案,并且已经 运行 解决了一些问题。

问题是:我有 2 组 Group 对象。这些集合在 email 上应该是唯一的(因此我们可以检查一组中的对象是否是另一组中的对象 in)。

但是,如果两个 Group 对象只有一个电子邮件匹配(例如,一个集合可能包含一个更新的 Group 对象,并且有一个新的 description).目标是有一个集合,我可以在其中仅基于 email 字段执行集合操作(​​交集和差集)...然后根据其他字段(descriptionname 检查相等性)

    class Group:
        def __init__(self, name, email, description):
            self.name = name
            self.email = email
            self.description = description

        def __hash__(self):
            return hash(self.email)

        def __eq__(self, other):
            return self.email == other.email 
                    and self.description == other.description 
                    and self.name == other.name

        def __ne__(self, other):
            return not self.__eq__(other)

        def __str__(self):
            return "Description: {0} Email: {1} Name: {2}".format(self.description, self.email, self.name)

所以我希望所有断言语句都在这里传递:

    group_1 = Group('first test group', 'testing@example.com', 'example description')
    group_2 = Group('second test group', 'real@example.com', 'example description')
    group_3 = Group('third group', 'testing@example.com', 'example description')
    group_5 = Group('updated name', 'testing@example.com', 'example description')

    group_set = set([group_1, group_2, group_3])
    group_set_2 = set([group_3, group_5])

    self.assertTrue(group_5 in group_set.intersection(group_set_2))
    self.assertEqual(2, len(group_set))
    self.assertTrue(group_5 in group_set)

Python 的 set 类型使用对象的 __eq__ 方法实现的相等性测试来确定对象是否 "the same" 作为其内容中的另一个对象。 __hash__ 方法只允许它找到其他元素以更有效地进行比较。因此,您希望使用基于不同于 __eq__ 方法的一组不同属性的 __hash__ 方法是行不通的。具有相同 __hash__ 值的多个不相等对象可以存在于同一个 set 中(尽管 set 由于散列冲突而效率稍低)。

如果您想要从电子邮件地址到 Group 的唯一映射,我建议使用字典,其中键是电子邮件地址,值是 Group 对象。这将让您确保电子邮件地址是唯一的,同时还让您以最合适的方式比较 Group 个对象。

要在两个这样的字典之间执行并集,请对一个字典的副本使用 update 方法:

union = dict_1.copy()
union.update(dict_2)

对于路口,使用字典理解:

intersection = {email: group for email, group in dict_2.iteritems() if email in dict_1}

这两个操作都将优先使用 dict_2 中的值而不是 dict_1 中的值,只要相同的电子邮件作为键出现在两者中。如果你想让它以另一种方式工作,只需切换字典名称即可。