必须将对象的所有属性都放在对象__hash__函数中吗?

时间:2018-01-11 00:55:14

标签: python hash

使用python 3.6

我已阅读docs

实施__hash__ 对象的所有属性必须在对象__hash__函数中吗?

那么这个例子还可以吗?

class Foo(object):

    def __init__(self, value):
        self.value = value
        self.not_important = 'irrelevant'

    def __hash__(self):
        return hash((self.value,))

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

foo.not_important在作为词典中的键时被修改

>>> foo = Foo(1)
>>> d = {foo:'foo is in d'}
>>> foo.not_important = 'something else'
>>> d[foo]
'foo is in d'
>>> bar = Foo(1)
>>> foo == bar
True
>>> d[bar]
'foo is in d'

foo.not_important实施时未使用__hash__。这完全可以吗?或者这可能是错误的?

2 个答案:

答案 0 :(得分:2)

没有。正如the documentation所述:

  

object.__hash__(self)

     

由内置函数hash()调用,以及对散列集合成员的操作,包括setfrozensetdict__hash__()应该返回一个整数。 唯一需要的属性是比较相等的对象具有相同的哈希值;建议将对象组件的哈希值混合在一起,这些组件的哈希值也通过将它们打包成元组并对元组进行哈希处理来对象进行比较。

在您的示例中,__eq____hash__仅使用self.value。这满足了唯一的要求。

答案 1 :(得分:2)

回答字面问题,可以省略__eq__未考虑的属性。事实上,你可以省去所有属性而只是return 0,虽然它会扼杀你的dict效率,所以不要这样做。

回答隐含的问题,只要你不以影响__eq____hash__的方式改变对象,就可以在它是dict键的情况下改变对象。例如,默认的__hash__实现根本不考虑它正在散列的对象的任何属性 - 它基于对象标识。使用默认的__hash____eq__,一个对象只等于它自己,你可以在不破坏dicts的情况下改变你想要的这个对象,而不是破坏dicts。