collections.ChainMap的目的是什么?

ale*_*cxe 60 python collections dictionary data-structures python-3.x

在Python 3.3中,一个ChainMap类被添加到collections模块中:

提供了一个ChainMap类,用于快速链接多个映射,以便将它们视为一个单元.它通常比创建新字典和运行多个update()调用快得多.

例:

>>> from collections import ChainMap
>>> x = {'a': 1, 'b': 2}
>>> y = {'b': 10, 'c': 11}
>>> z = ChainMap(y, x)
>>> for k, v in z.items():
        print(k, v)
a 1
c 11
b 10
Run Code Online (Sandbox Code Playgroud)

它是由动机这个问题,并通过公开这一个(没有PEP创建).

据我所知,它是一个替代,有一个额外的字典,并用update()s 维护它.

问题是:

  • 用例ChainMap包括哪些用例?
  • 有真实世界的例子ChainMap吗?
  • 它是否用于切换到python3的第三方库?

额外问题:有没有办法在Python2.x上使用它?


我在Transforming Code into Beautiful, Idiomatic PythonRayCon Hettinger的PyCon演讲中听说过它,我想将它添加到我的工具包中,但我不知道何时应该使用它.

shx*_*hx2 61

我喜欢@ b4hand的例子,实际上我在过去使用的类似ChainMap的结构(但不是ChainMap本身)中使用了他提到的两个目的:多层配置覆盖和变量堆栈/范围仿真.

ChainMap与使用dict-update循环相比,我想指出另外两个动机/优点/差异,因此只存储"最终"版本":

  1. 更多信息:由于ChainMap结构是"分层的",它支持回答问题:我是否获得"默认"值或被覆盖的值?什么是原始("默认")值?在什么级别上覆盖了值(借用@ b4hand的配置示例:user-config或命令行覆盖)?使用简单的词典,回答这些问题所需的信息已经丢失.

  2. 速度权衡:假设你有N层和M每个键中最多的键,构造一个ChainMap O(N),每个查找O(N)最坏情况[*],而使用更新循环构造一个dict O(NM)并进行每次查找O(1).这意味着如果你经常构造并且每次只执行一些查找,或者如果M很大,ChainMap的懒惰构造方法对你有利.

[*](2)中的分析假定dict-access是O(1),实际上它是O(1)平均的,O(M)最坏的情况.在这里查看更多细节.

  • +1这是一个合理的比较.与其他技术有一些类比会很好.例如,操作系统命令行具有路径的概念,该路径基本上是目录查找链,直到找到匹配为止.在Python中,将使用ChainMap建模. (8认同)

b4h*_*and 36

我可以看到ChainMap用于配置对象,其中有多个配置范围,如命令行选项,用户配置文件和系统配置文件.由于查找按构造函数参数中的顺序排序,因此您可以覆盖较低范围的设置.我没有亲自使用或看到过ChainMap使用过,但这并不奇怪,因为它是标准库的最新版本.

如果您尝试自己实现词法范围,那么在模拟堆栈帧时,如果您推送和弹出变量绑定,它也可能很有用.

ChainMap标准库文档提供了几个示例以及第三方库中类似实现的链接.具体来说,它命名Django的Context类和Enthought的MultiContext类.

  • +1这是一个很好的答案,涵盖了替代实现和链接到文档中提到的链接名称空间的多个示例. (5认同)

Bob*_*bHy 6

我会抓住这个:

Chainmap看起来像是一种非常简单的抽象.对于一个非常特殊的问题,这是一个很好的解决方案.我提出这个用例.

如果你有:

  1. 多个映射(例如,dicts)
  2. 这些映射中的一些键重复(相同的键可以出现在多个映射中,但不是所有键都出现在所有映射中的情况)
  3. 希望在"最高优先级"映射中访问密钥值的消费应用程序,其中对于任何给定密钥的所有映射都存在总排序(即,映射可能具有相同的优先级,但仅在已知这些映射中没有密钥的重复)(在Python应用程序中,包可以存在于同一目录中(相同的优先级)但必须具有不同的名称,因此,根据定义,该目录中的符号名称不能重复.)
  4. 消费应用程序不需要更改密钥的值
  5. 同时映射必须保持其独立的身份,并且可以由外部力量异步地改变
  6. 并且映射足够大,价格足以访问,或者在应用程序访问之间经常更改,每次应用程序需要时计算投影(3)的成本是您应用程序的重要性能问题...

然后,您可以考虑使用链图来创建映射集合的视图.

但这都是事后的理由.Python人员遇到了问题,在他们的代码环境中提出了一个很好的解决方案,然后做了一些额外的工作来抽象他们的解决方案,以便我们可以选择使用它.给他们更多的力量.但是,是否适合您的问题由您决定.


A T*_*A T 5

不完美地回答您的问题:

额外的问题:是否可以在Python2.x上使用它?

from ConfigParser import _Chainmap as ChainMap
Run Code Online (Sandbox Code Playgroud)

但是请记住,这不是真实的ChainMap,它继承自DictMixin并且仅定义:

__init__(self, *maps)
__getitem__(self, key)
keys(self)

# And from DictMixin:
__iter__(self)
has_key(self, key)
__contains__(self, key)
iteritems(self)
iterkeys(self)
itervalues(self)
values(self)
items(self)
clear(self)
setdefault(self, key, default=None)
pop(self, key, *args)
popitem(self)
update(self, other=None, **kwargs)
get(self, key, default=None)
__repr__(self)
__cmp__(self, other)
__len__(self)
Run Code Online (Sandbox Code Playgroud)

它的实现似乎也不是特别有效。