2016-12-31 36 views
2

我读过列表不能被散列的字典键。 然而,自定义对象似乎是可变的还有:字典键:自定义对象vs列表

# custom object 
class Vertex(object): 
    def __init__(self, key): 
     self.key = key 

v = Vertex(1) 
v.color = 'grey' # this line suggests the custom object is mutable 

但是,与清单,它们可以被用来作为字典键;为什么是这样?难道我们不能仅仅在这两种情况下散列某种类型的id(例如内存中对象的地址)?

+0

请注意,您的类没有定义'__eq__'。 – o11c

回答

4

Why Lists can't be Dictionary Keys指出:

列为字典键

这就是说,简单的答案,为什么清单不能作为字典键是列表不提供有效的散列方法。当然,显而易见的问题是,“为什么不呢?”

考虑可以为列表提供哪种散列函数。

如果列表按照id进行散列,给定Python的散列函数定义,这肯定是有效的 - 具有不同散列值的列表将具有不同的ID。但是列表是容器,而其他大多数操作都是这样处理的。因此,通过它们的ID哈希表,而不是会产生意想不到的行为,例如:

  1. 仰望不同列表具有相同的内容会产生不同的结果,即使比较具有相同内容的列表会显示它们等同。

  2. 在字典查找中使用列表文字将毫无意义 - 它总会产生KeyError。

用户定义类型的字典键的

怎么样的情况下,用户定义类型?

默认情况下,所有用户定义的类型都可用作缺省为id(对象)的散列(对象)和缺省为cmp(id(object1),id(object2))的cmp(object1,object2)的字典键。上面对列表讨论了同样的建议,结果令人不满意。为什么用户定义的类型不同?

  1. 在对象必须放置在映射中的情况下,对象标识通常比对象内容重要得多。

  2. 在对象内容确实很重要的情况下,可以通过重写__hash____cmp____eq__来重新定义默认设置。

注意,它往往是更好的做法,当一个对象被与一个值,简单地分配一个值作为对象的属性之一。