Python MappingProxyType和PEP 416 frozendict之间的差异

Python MappingProxyType和PEP 416 frozendict之间的差异,python,python-3.x,immutability,Python,Python 3.x,Immutability,在Python3.3的公共API中添加了一个相关的类types.MappingProxyType 我知道MappingProxyType只是底层dict的包装,但尽管如此,它在功能上不等同于frozendict 换句话说,最初的PEP 416frozendict与此有什么实质性区别: from types import MappingProxyType def frozendict(*args, **kwargs): return MappingProxyType(dict(*args, *

在Python3.3的公共API中添加了一个相关的类
types.MappingProxyType

我知道
MappingProxyType
只是底层
dict
的包装,但尽管如此,它在功能上不等同于
frozendict

换句话说,最初的PEP 416
frozendict
与此有什么实质性区别:

from types import MappingProxyType
def frozendict(*args, **kwargs):
  return MappingProxyType(dict(*args, **kwargs))
当然,
MappingProxyType
不能按原样散列,但同样,在确保其所有值都可散列后,可以将其设置为可散列(MappingProxyType不能子类化,因此需要组合和转发方法)。

TL;博士
MappingProxyType
是映射(如dict)对象的只读代理

frozendict
是一个不可变的dict

答复 代理模式为(引用):

代理,在其最一般的形式中,是一个充当代理的类 与其他事物的接口

MappingProxyType
只是一个简单的代理(即接口),用于访问真实对象(真实映射,在我们的示例中是dict)

建议的
frozendict
对象与设置为frozenset的对象相同。只读(不可变)对象,只能在创建时更改

那么为什么我们需要
映射ProxyType
?示例用例是您希望将字典传递给另一个函数,但如果它无法更改您的字典,它将充当只读代理(引用):

映射的只读代理。它在屏幕上提供了一个动态视图 映射的条目,这意味着当映射更改时,视图 反映了这些变化

让我们看看
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,所以我们无法确定它的实现是什么。 通过查看政治公众人物,我们可以看到:

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


我假设PEP的一部分是内存优化,这种frozendict的实现可能会受益于使用
\uuuuu散列实现的dict比较性能。

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

d={'a':1,'b':2}
从frozendict导入frozendict
fd=冻结dict(d)
fd2=fd.copy(b=3,c=5)
从类型导入MappingProxyType
mp=映射ProxyType(d)
#mp2=mp.copy(b=3,c=5)=>TypeError:copy()不接受关键字参数
#要做到这一点,我们需要更多的生物板
温度=dict(mp)
临时更新(b=3,c=5)
mp2=映射ProxyType(临时)

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

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

是的,但我的问题是,被拒绝的
frozendict
与您可以创建为
MappingProxyType
的薄包装之间是否存在实质性差异。你能举一些代码的例子吗?这些代码可以与(被拒绝的)PEP 416
frozendict
一起使用,但不能与我在问题中定义的
frozendict
一起使用?frozendict可以使用字典作为键或创建一组字典。MappingProxyType对象不能用作dict key或set元素,因为它们在其生命周期中可能会间接变异,从而可能破坏唯一性不变。因此,到目前为止的区别是1)MPT不可散列,因此具有更大范围的可接受键值,2)MPT不可子类化。为什么它不可子分类?@Dubslow。如果非要我猜的话,那是因为实现它的C魔法是这么说的。以下是C接口: