字典键:自定义对象与列表

时间:2016-12-31 03:29:34

标签: python list dictionary

我已经读过列表不能是字典键,因为不能对可变对象进行哈希处理。 但是,自定义对象似乎也是可变的:

# 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(例如内存中对象的地址)吗?

1 个答案:

答案 0 :(得分:4)

Why Lists can't be Dictionary Keys中所述:

  

列为词典键

     

也就是说,为什么列表不能用作字典键的简单答案是列表不提供有效的哈希方法。当然,显而易见的问题是,"为什么不呢?"

     

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

     

如果列表经过id散列,那么鉴于Python对散列函数的定义,这肯定是有效的 - 具有不同散列值的列表将具有不同的ID。但是列表是容器,并且它们上的大多数其他操作都是如此处理它们。因此,它们的id的散列列表会产生意外的行为,例如:

     
      
  1. 查找具有相同内容的不同列表会产生不同的结果,即使比较具有相同内容的列表也会表明它们是等效的。

  2.   
  3. 在字典查找中使用列表文字是没有意义的 - 它总会产生KeyError。

  4.         

    用户定义的类型作为字典键

         

    用户定义类型的实例怎么样?

         

    默认情况下,所有用户定义的类型都可用作字典键,哈希(对象)默认为id(对象),cmp(object1,object2)默认为cmp(id(object1),id(object2))。上面针对列表讨论了同样的建议,但发现并不令人满意。为什么用户定义的类型不同?

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

    2.   
    3. 如果对象内容确实很重要,可以通过覆盖__hash____cmp____eq__来重新定义默认设置。

    4.         

      请注意,当一个对象与一个值相关联时,通常更好的做法是简单地将该值指定为对象的一个​​属性。