Collections--ChainMap
一个 ChainMap
类是为了将多个映射快速的链接到一起,这样它们就可以作为一个单元处理。它通常比创建一个新字典和多次调用 update()
要快很多。
class collections.
ChainMap
(*maps)
支持所有常用字典方法。另外还有一个 maps 属性(attribute),一个创建子上下文的方法(method), 一个存取它们首个映射的属性(property):
new_child
(m=None)-
返回一个新的
ChainMap
类,包含了一个新映射(map),后面跟随当前实例的全部映射(map)。如果m
被指定,它就成为不同新的实例,就是在所有映射前加上 m,如果没有指定,就加上一个空字典,这样的话一个d.new_child()
调用等价于ChainMap({}, *d.maps)
。这个方法用于创建子上下文,不改变任何父映射的值。在 3.4 版更改: 添加了
m
可选参数。
parents
-
属性返回一个新的
ChainMap
包含所有的当前实例的映射,除了第一个。这样可以在搜索的时候跳过第一个映射。
现在假设你必须在两个字典中执行查找操作 (比如先从 a 中找,如果找不到再在 b中找)。一个非常简单扼解决方案就是使用 collections 模块中的 ChainMap 类。比如:
In [46]: a = {'x': 1, 'z': 3 } In [47]: b = {'y': 2, 'z': 4 } In [48]: from collections import ChainMap In [49]: c=ChainMap(a,b) In [50]: c.get('x') Out[50]: 1 In [51]: c.get('z') Out[51]: 3 In [52]: c.get('y') Out[52]: 2
如果出现重复键,那么第一次出现的映射值会被返回。因此,例子程序中的c['z']总是会返回字典a中对应的值,而不是b中对应的值。
对于字典的更新或删除操作总是影响的是列表中第一个字典。比如:
In [65]: c Out[65]: ChainMap({'x': 1, 'z': 10}, {'y': 2, 'z': 4}) In [66]: c['x']=10 In [67]: c['z']=10 In [68]: c Out[68]: ChainMap({'x': 10, 'z': 10}, {'y': 2, 'z': 4}) del c['y'] KeyError: "Key not found in the first mapping: 'y'"
一个 ChainMap
通过引用合并底层映射。 所以,如果一个底层映射更新了,这些更改会反映到 ChainMap
。
In [71]: a['x']=100 In [72]: c Out[72]: ChainMap({'x': 100, 'z': 10}, {'y': 2, 'z': 4})
new_child()方法和parents属性
d=c.new_child() In [81]: d Out[81]: ChainMap({}, {'x': 100, 'z': 10}, {'y': 2, 'z': 4}) In [82]: d['x']=1 In [83]: d Out[83]: ChainMap({'x': 1}, {'x': 100, 'z': 10}, {'y': 2, 'z': 4}) In [84]: d=d.new_child() In [85]: d['x']=2 In [86]: d Out[86]: ChainMap({'x': 2}, {'x': 1}, {'x': 100, 'z': 10}, {'y': 2, 'z': 4}) In [89]: d=d.parents In [90]: d['x'] Out[90]: 1 In [91]: d Out[91]: ChainMap({'x': 1}, {'x': 100, 'z': 10}, {'y': 2, 'z': 4}) In [92]: d=d.parents In [93]: d['x'] Out[93]: 100
典型用例
让用户指定的命令行参数优先于环境变量,优先于默认值的例子
import os, argparse defaults = {'color': 'red', 'user': 'guest'} parser = argparse.ArgumentParser() parser.add_argument('-u', '--user') parser.add_argument('-c', '--color') namespace = parser.parse_args() command_line_args = {k:v for k, v in vars(namespace).items() if v} combined = ChainMap(command_line_args, os.environ, defaults) print(combined['color']) print(combined['user'])