【问题标题】:Python: Can a custom mutable class be used as a key for a dictionary?Python:自定义可变类可以用作字典的键吗?
【发布时间】:2019-11-26 22:43:11
【问题描述】:

假设我们有一个这样的自定义节点类:

class Node:
    def __init__(self, val, next, random):
        self.val = val
        self.next = next
        self.random = random

我有一个节点对象,我想将它用作字典的键。
我的理解是,一个对象应该是不可变的和可散列的,才能可靠地用作字典键,因为可变对象可能导致散列值发生变化,而该对象是可变的。

我知道 python 确实允许将自定义可变对象用作字典键,它是如何工作的?

更新:引用的链接不涉及自定义对象的可变性方面。它们只是提供了一种方法来覆盖散列函数的默认实现。此问题应重新打开,因为它与引用的“重复”问题不同。

答案:自定义可变对象的哈希方法的默认实现使用identity,它保证在对象的生命周期内是唯一且恒定的。一个可变的自定义对象不应该覆盖散列函数的默认实现。下面提供更详细的答案。

【问题讨论】:

  • 它部分回答了我的问题,因为它采用了一个非常具体的示例,其中类只有一个不可变的“str”类型属性。我将回答这个问题,因为我想出了如何将具有多个属性的类对象用作字典的键,即使它具有可变的属性。
  • @Anatolii 恐怕这个问题必须打开,因为参考链接不是我问题的准确答案。能做到吗?
  • 当然,但是,在您的问题中,您应该解释为什么这些链接不是正确的答案。否则,您将无法获得足够的支持(除了我之外)来重新提出问题。
  • 我当时投票决定重新提出您的问题。

标签: python-3.x hashmap hashtable immutability


【解决方案1】:

节点自定义对象在其类定义中是可变的,并且任何可变对象都不应覆盖哈希方法的默认实现,因为默认方法使用identity,保证对象的唯一且恒定寿命。这样做可能会导致对象的哈希值发生变化,从而导致很多问题。

例如:

Node node = new Node(5, None, None)
cache = {}
cache[node] = "Node added"
node.val = 5

# If we override default implementation of hash function, we have to
# make sure hashing function does not use object attributes else
# accessing cache[node] now would cause problem as a different hashed 
# value would be computed and we won't be able to retrieve "Node added" 
# value. 

# Default implementation uses identity and would always hash 
# to same value even if the object mutates.

但我们可以继续为不可变对象重写 hash 方法。在this 线程上的回答帮助我了解它是如何工作的。对于以下内容,我们将假设 Node 对象的属性一旦创建就永远不会改变。

这里的想法是确保您的自定义对象实现哈希和相等方法。

Equality 方法应该以这样一种方式实现,即两个逻辑等价对象总是被认为是相等的。对于此处给定的 Node 对象,如果两个节点的所有属性都相同,则它们将被视为相等。所以我们可以构建一个键,它是所有属性的元组。这是可行的,因为元组是不可变的,所以我们基本上是在创建一个包含对象所有属性的不可变对象,并将使用它来计算哈希。

以下实现确保两个逻辑上等效的节点(具有相同的属性)具有相同的键,因此将为两个相等的节点生成相同的哈希值。

class Node:
    def __init__(self, val, next, random):
        self.val = val
        self.next = next
        self.random = random

    def __key(self):
        return (self.val, self.next, self.random)

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

    def __eq__(self, other):
        if isinstance(other, Node):
            return self.__key() == other.__key()
        return NotImplemented

【讨论】:

    猜你喜欢
    • 2012-03-18
    • 2013-01-26
    • 1970-01-01
    • 2013-12-03
    • 1970-01-01
    • 2016-06-03
    • 2011-03-08
    • 2011-11-25
    • 2014-07-14
    相关资源
    最近更新 更多