MappingProxyType和PEP 416 frozendict之间的区别

时间:2017-01-22 19:16:57

标签: python python-3.x immutability

frozendict was rejected期间,相关的类types.MappingProxyType已添加到python 3.3中的公共API。

我理解MappingProxyType只是基础dict的包装,但尽管不是它在功能上等同于frozendict吗?

换句话说,原始PEP 416 frozendict与此之间存在实质性差异:

from types import MappingProxyType
def frozendict(*args, **kwargs):
  return MappingProxyType(dict(*args, **kwargs))

当然MappingProxyType不是可以清除的,但是就像the PEP suggested for frozendict一样,在确保其所有值都是可清除的之后可以使它成为可哈希的(MappingProxyType不能被子类化,因此需要组合并转发方法)。

4 个答案:

答案 0 :(得分:6)

TL; DR

MappingProxyType是映射(例如dict)对象的只读代理。

frozendict是一个不可变的词典

答案

代理模式是(引用wikipedia):

  

代理,最常见的形式,是一个充当的类   接触其他东西。

MappingProxyType只是一个访问真实对象的简单代理(即界面)(真实地图,在我们的例子中是dict)。

建议的frozendict对象与冻结集一样。只读(不可变)对象,只能在创建时更改。

那么为什么我们需要MappingProxyType?示例用例是您希望将字典传递给另一个函数但不能更改字典的情况,它充当只读代理,(引用python docs):

  

映射的只读代理。它提供了动态视图   映射的条目,表示映射更改时的视图   反映了这些变化。

让我们看一下MappingProxyType

的一些示例用法
In [1]: from types import MappingProxyType
In [2]: d = {'a': 1, 'b': 2}
In [3]: m = MappingProxyType(d)
In [4]: m['a']
Out[4]: 1
In [5]: m['a'] = 5
TypeError: 'mappingproxy' object does not support item assignment
In [6]: d['a'] = 42
In [7]: m['a']
Out[7]: 42
In [8]: for i in m.items():
...:     print(i)

('a', 42)
('b', 2)

更新

因为PEP没有进入python,我们无法确定实现的是什么。 通过观察PEP我们看到:

frozendict({'a': {'b': 1}})

会引发异常,因为{'b': 1}不是可散列的值,但在您的实现中它将创建对象。当然,您可以按照PEP中的说明添加值的验证。

我假设PEP的一部分是内存优化,并且这种冻结的实现可以从使用__hash__实现的dict比较的性能中受益。

答案 1 :(得分:0)

我注意到的一件事是frozendict.copy支持添加/替换(限于字符串键),而MappingProxyType.copy不支持。例如:

d = {'a': 1, 'b': 2} 

from frozendict import frozendict
fd = frozendict(d)
fd2 = fd.copy(b=3, c=5)

from types import MappingProxyType
mp = MappingProxyType(d)
# mp2 = mp.copy(b=3, c=5) => TypeError: copy() takes no keyword arguments
# to do that w/ MappingProxyType we need more biolerplate
temp = dict(mp)
temp.update(b=3, c=5)
mp2 = MappingProxyType(temp)

注意:这两个不可变映射都不支持“删除并返回新的不可变副本”操作。

答案 2 :(得分:0)

MappingProxyType仅在第一级上添加不变性:

>>> from types import MappingProxyType
>>> d = {'a': {'b': 1}}
>>> md = MappingProxyType(d)
>>> md
mappingproxy({'a': {'b': 1}})
>>> md['a']['b']
1
>>> md['a']['b'] = 3
>>> md['a']['b']
3

答案 3 :(得分:0)

MappingProxyType 也非常慢。我建议你使用 frozendict

PS:我是包裹的新主人