MappingProxyType和PEP 416 frozendict之间的区别

max*_*max 11 python immutability python-3.x

虽然frozendict 被拒绝了,但是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))
Run Code Online (Sandbox Code Playgroud)

当然MappingProxyType不是像现在这样可以清洗,但正如PEP所建议的那样frozendict,它可以在确保其所有值都是可清除之后可以使用(MappingProxyType不能被子类化,因此需要组合和转发方法).

Ale*_*rub 10

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
Run Code Online (Sandbox Code Playgroud)

  • 这显然与 freezedict 相同...... (4认同)

Shm*_*ikA 7

TL; DR

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

frozendict 是一个不可改变的词典

回答

代理模式是(引用维基百科):

代理以其最一般的形式,是一个充当其他东西的接口的类.

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

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

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

映射的只读代理.它提供了映射条目的动态视图,这意味着当映射发生更改时,视图会反映这些更改.

让我们看看一些示例用法 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)
Run Code Online (Sandbox Code Playgroud)

更新:

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

frozendict({'a': {'b': 1}})
Run Code Online (Sandbox Code Playgroud)

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

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

  • 是的,但我的问题是被拒绝的`frozendict`和你可以创建的`mappedProxyType`的瘦包装器之间是否有任何实质性的区别.你能给出一些与(被拒绝的)PEP 416`frozendict`一起使用的代码的例子,但不能用我在我的问题中定义的`frozendict`吗? (4认同)
  • frozendict 将允许使用字典作为键或制作一组字典。MappingProxyType 对象不能用作 dict 键或 set 元素,因为它们可能会在其生命周期中间接发生变异,这可能会破坏唯一性不变性。 (2认同)
  • @ShmulikA 是的,这是正常的。不要求不可变对象中的所有对象都必须是不可变的。例如,元组是不可变类型,但您可以拥有列表元组。在这种情况下,元组根本不可散列。如果你想要深度不变性,可以使用 gelidum:https://github.com/diegojromerolopez/gelidum (2认同)