关于类:如何在python中创建不可变字典?

How to create an immutable dictionary in python?

我想在python中使用subclassdict,这样子类的所有字典都是不可变的。

我不明白__hash__是如何影响不变的,因为在我的理解中,它只是表示物体的平等或不平等!

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

更新:

目标是API的公共响应可以作为dict提供,必须作为全局变量共享。所以,不管怎样,它都需要完好无损?


我找到了一个官方的参考资料:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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/


So, can __hash__ be used to implement immutability ?

不,它不能。对象可以变(或不变),不管它的__hash__方法做什么。

不可变对象与__hash__之间的关系是,由于不可变对象不能更改,__hash__返回的值在构造后保持不变。对于可变对象,可能是这样,也可能不是这样(建议的做法是这样的对象不能哈希)。

关于进一步的讨论,见第13707号问题:澄清hash()施工期。


关于哈希性和可变性之间的关系:

为了有用,哈希实现需要满足以下属性:

  • 使用==比较equal的两个对象的哈希值必须相等。

  • 哈希值可能不会随时间变化。

  • 这两个属性意味着在比较实例时,哈希类不能考虑可变属性,相反,在比较实例时,确实考虑可变属性的类是不可哈希的。不可变类可以成为可哈希类,而不需要进行任何比较。

    所有内置可变类型都不可哈希,所有不可变内置类型都可哈希。这主要是上述观察的结果。

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

    使类可散列并不能以某种神奇的方式使其不可变。相反,要使字典在保持原始比较运算符的同时以合理的方式具有哈希性,首先需要使其不可变。

    编辑:关于您的更新:

    提供全局不可变字典等效项的方法有以下几种:

  • 使用collections.namedtuple()实例代替。

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

  • 我通常会这样做:

    1
    2
    3
    4
    _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值来解决此问题。