2012-06-13 78 views
3

我想subclassdict在Python中,这样的子类的所有字典是不可变的。如何在python中创建一个不可变的字典?

我不明白怎么做__hash__影响不变性,因为在我的理解,它只是意味着该平等对象的非平等

那么,__hash__可以用来实现不变性?怎么样 ?

更新

目的是从API常见的反应可作为一个字典,其具有作为全局变量被共享。那么,无论如何,这都需要保持完整。

+0

这已经被问了很多次之前(不幸的是,我没有方便的链接现在)。对于大多数问题,试图制作不可变的字典是错误的方法。你究竟想达到什么目的? –

+3

这个链接怎么样:http://stackoverflow.com/q/2703599/623518 – Chris

+0

我只会重写你的字典的__setitem __()'方法。但请注意,这并不能保证你的字典的值是不可变的(例如,你的值是列表,例如)。 –

回答

3

我发现了一个官方参考:

class imdict(dict): 
    def __hash__(self): 
     return id(self) 

    def _immutable(self, *args, **kws): 
     raise TypeError('object is immutable') 

    __setitem__ = _immutable 
    __delitem__ = _immutable 
    clear  = _immutable 
    update  = _immutable 
    setdefault = _immutable 
    pop   = _immutable 
    popitem  = _immutable 

署名:http://www.python.org/dev/peps/pep-0351/

+0

最后,工作真棒,加上一个更有信心的来源。 –

5

那么,__hash__可以用来实现不变性吗?

不,它不能。无论对象的方法如何,该对象都可以变为可变的(或不变)。

不可变对象与__hash__之间的关系是,由于无法更改不可变对象,所以__hash__返回的值在构建后保持不变。对于可变对象,这可能会也可能不是这种情况(推荐的做法是这些对象根本无法散列)。

有关进一步的讨论,请参阅Issue 13707: Clarify hash() constency period

+0

那么,默认情况下,用户定义的类都是可变和可哈希的,但哈希将始终保持不变! –

+0

@SvenMarnach:你说的是真的。我说的也是如此。 TBH,我没有看到你的推理线路在哪里...... – NPE

+0

我只是建议你的答案的最后一句话有些不完整。关于不变性和可否性之间的关系还有更多。 –

3

关于hashability和可变性之间的关系:

为了有用,散列实现需要满足以下性质:

  1. 使用==必须是比较相等的两个对象的哈希值等于。

  2. 散列值可能不会随时间而改变。

这两个属性意味着比较实例时,哈希的类不能采取可变的特性考虑,并通过对位的是里面做类采取可变属性考虑在内时,比较实例不是可哈希。不可变的类可以进行哈希,没有任何比较的影响。

所有内置的可变类型都不可散列,并且所有不可变的内置类型都是可散列的。这主要是上述观察的结果。

默认情况下,用户定义的类根据对象标识定义比较,并使用id()作为散列。它们是可变的,但在比较实例时不会考虑可变数据,因此它们可以变为可散列的。

制作一个可拆分的类并不会使它在一些神奇的方式中不可变。相反,为了使字典在保持原始比较运算符的同时以合理的方式可散列化,首先需要使它不可变。

编辑:关于你提到的更新:

有几种方法,以提供全球不可改变字典相当于:

  1. 使用collections.namedtuple()实例,而不是。

  2. 使用具有只读属性的用户定义的类。

  3. 我通常像这样的东西去:

    _my_global_dict = {"a": 42, "b": 7} 
    
    def request_value(key): 
        return _my_global_dict[key] 
    

    通过领先的下划线,你清楚地表明_my_global_dict是一个实现细节不被应用程序代码被感动。请注意,如果代码碰巧是可变对象,则此代码仍然允许修改字典。如有必要,您可以通过返回copy.copy() s或copy.deepcopy() s来解决此问题。

+0

所以,请给出一些可以使它成为'不可变'的代码? 由于这只是答案的一半! –

+1

@YugalJindle:正如我以前多次说过的,使用不可变的字典很可能是您的问题的错误解决方案,但只有告诉我们您的问题实际是什么,我们才能告诉您。 (此外,我的印象是,你对一个好的解决方案并不感兴趣,并且你没有真正关注答案和评论。否则,你已经找到了一些示例代码,这在上面的评论中被链接了。) –

+0

@YugalJindle:不,它当然不是你的情况中唯一的解决方案。再次,代码是针对您的问题的第二个评论中链接的不可变字典。 –

相关问题