collections.ChainMap的目的是什么?

时间:2014-04-30 16:07:06

标签: python python-3.x dictionary data-structures collections

在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

this issue推动,并由this one公开(未创建PEP)。

据我了解,它可以替代使用额外字典并使用update()进行维护。

问题是:

  • ChainMap涵盖哪些用例?
  • 是否有ChainMap的真实世界示例?
  • 是否在第三方库中使用切换到python3?

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


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

4 个答案:

答案 0 :(得分:53)

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

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

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

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

  3. [*](2)中的分析假设dict-access为M,实际上平均为O(1)O(1)最差。查看更多详情here

答案 1 :(得分:32)

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

如果你试图自己实现一个词法范围,那么在你推送和弹出变量绑定的情况下模拟堆栈帧也可能很有用。

standard library docs for ChainMap给出了几个示例以及第三方库中类似实现的链接。具体来说,它命名为Django的Context class和Enthought的MultiContext class

答案 2 :(得分:6)

我会对此采取行动:

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

如果你有:

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

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

答案 3 :(得分:4)

不完美地回答你:

  

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

from ConfigParser import _Chainmap as ChainMap

但请注意,这不是真正的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)

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