如果对象的__hash__ __ ________________________

问题描述 投票:0回答:2
在python中,我知道该对象的寿命应该相同的值

__hash__

返回给定对象的值。但是,出于好奇,如果不是,会发生什么呢?这会导致什么样的破坏?

class BadIdea(object): def __hash__(self): return random.randint(0, 10000)
我知道

__contains__

__getitem__
o

会表现得奇怪,因此,命令和场景会奇怪。您可能最终会在dict/set中以“孤儿”值。

还会发生什么?它会崩溃口译员还是损坏的内部结构?

python hashcode
2个回答
18
投票
您的主要问题确实与命令和集合有关。如果将对象插入dict/set,并且该对象的哈希发生变化,那么当您尝试检索该对象时,您最终会在DICT/SET的下面的数组中查看

divent的斑点,因此找不到对象。这就是为什么dict Keys应该始终不变的原因。 这里是一个很小的例子:假设我们将o

放在一个dict中,而

o

的初始哈希是3。

牌表: 0 1 2 3 4 5 6 7 +----+---+---+---+ - +---+---+ - + - +---+ | | | | O | | | | | +----+---+---+---+ - +---+---+ - + - +---+ ^ 我们将O放在这里,因为它是3
现在,假设更改为

6
的哈希。如果我们想从dict中检索
o

,我们会看地点

6
,但是那里什么都没有!在查询数据结构时,这将导致假阴性。实际上,在dict的情况下,上面数组的每个元素都可能具有与之相关的“值”,并且一个位置可能会有多个元素(例如,a
hashcollision
)。另外,我们通常会在决定放置元素的位置时,将哈希值模量的大小为数组的大小。但是,不管所有这些细节如何,上面的示例仍然准确地传达出当对象的哈希代码更改时可能出了什么问题。

  
它会崩溃解释器,还是损坏的内部结构?
没有,这不会发生。当我们说一个物体的哈希变化是“危险的”时,我们的意思是危险的,因为它本质上会破坏哈希的目的,并使代码很难甚至不可能推理。我们并不是说可能会导致坠机事件的意义。

在Github上有一篇很棒的文章:
当您惹上Hashing

时会发生什么。 首先,您需要知道Python的期望(在文章中引用):


8
投票

对象的哈希不会在对象的寿命上发生变化(换句话说,悬空对象应该是不可变的)。

    a == b
  • 意味着

    hash(a) == hash(b)

    (请注意,在哈希碰撞的情况下可能不存在反面)。
  • the的代码示例,显示了变体哈希的问题,具有略有不同的类示例,但是这个想法仍然相同:

    >>> class Bad(object): 
    ...     def __init__(self, arg): 
    ...         self.arg = arg 
    ...     def __hash__(self): 
    ...         return hash(self.arg) 
    ... 
    >>> Bad(1) 
    <__main__.Bad object at ...> 
    >>> hash(Bad(1)) 
    1 
    >>> a = Bad(1) 
    >>> b = {a:1} 
    >>> a.arg = 2 
    >>> hash(a) 
    2 
    >>> b[a] 
    Traceback (most recent call last):
    ...
    KeyError: <__main__.Bad object at ...>
    
    在这里,我们通过突变用于计算哈希的A的论点来隐式更改A的哈希。结果,该对象不再在字典中找到,该字典使用哈希查找对象。
    

  • 注意,Python并不能阻止我这样做。如果需要的话,我可以做到这一点,从而使
__setattr__

升起

AttributeError
,但是即使到那时,我也可以通过修改对象的
__dict__
来强制更改它。这就是我们说Python是一种“同意成年人”语言时的含义。

它不会使python崩溃
,但意外的行为将在dict/set和基于对象哈希的所有事物中发生。


最新问题
© www.soinside.com 2019 - 2025. All rights reserved.