ChainMap
chainMap 属于Python collections 模块下的一个子类,作用是将多个字典,组织成一个字典。当查询时,会按照构造时传入的字典的顺序进行查询。它比使用这些字典创建一个新字典要快。
简单示例
python
# 导入ChainMap模块
from collections import ChainMap
h1 = {"a": 1, "b": 2, "c": 3}
h2 = {"a": 10, "b": 20, "d": 30}
# 将h1, h2组织成一个字典
h = ChainMap(h1, h2)
# 在第一个字典中查到了"a"这个key,返回该key对应的value
print(h["a"])
# 1
# 在第一个字典中没有查到了"a"这个key,然后在第二个字典的中查到了这个key,返回该key对应的value
print(h["d"])
#30
什么时候使用呢?
在Python中,配置文件通常是字典,系统配置和个人私有配置同时存在时候,可以使用ChainMap来构造出最终配置文件,构造时候个人私有配置在前,系统配置在后。这样,在使用的时候,个人配置就能覆盖系统配置。
常用操作
-
初始化:
chain_map = ChainMap(*maps)
传入若干个字典,用来初始化。例如:
chain_map = ChainMap(h1, h2)
。这样就将多个字典组合在一起了。如果在初始化的时候,没有传入字典参数,则默认传入一个空字典。底层是将传入字典的引用保存在一个列表中。 -
查询:查询时,依次查询每个字典,直到一个键被找到,并返回该值。
pythonfrom collections import ChainMap h1 = {"a": 1, "b": 2, "c": 3} h2 = {"a": 10, "b": 20, "d": 30} h = ChainMap(h1, h2) # 搜索操作会依次对字典进行搜索,返回第一个值 print(h["a"]) # 1 print(h["d"]) #30
这样的目的是,让后面字典保持不变。例如第一个字典是私人配置,第二个字典是系统配置,操作只会影响个人配置,不会影响系统配置,这对于系统配置来说,是很重要的。
-
新增:新增键值对只操作第一个字典。
pythonfrom collections import ChainMap h1 = {"a": 1, "b": 2, "c": 3} h2 = {"a": 10, "b": 20, "d": 30} h = ChainMap(h1, h2) # 新增操作只会对第一个字典进行操作,因为保存的是引用,因此,本质上是原字典执行的新增操作 h["x"] = 10000 print(h)# 只对第一个字典进行新增 # ChainMap({'a': 1, 'b': 2, 'c': 3, 'x': 10000}, {'a': 10, 'b': 20, 'd': 30}) print(h1) # {'a': 1, 'b': 2, 'c': 3, 'x': 10000}
这样的目的是,让后面字典保持不变。例如第一个字典是私人配置,第二个字典是系统配置,操作只会影响个人配置,不会影响系统配置,这对于系统配置来说,是很重要的。
-
更新:更新键值对只会操作第一个字典。
pythonfrom collections import ChainMap h1 = {"a": 1, "b": 2, "c": 3} h2 = {"a": 10, "b": 20, "d": 30} h = ChainMap(h1, h2) # 更新操作只会对第一个字典进行操作,因为保存的是引用,因此,本质上是原字典执行的更新操作 h["a"] = 99 print(h) # ChainMap({'a': 99, 'b': 2, 'c': 3}, {'a': 10, 'b': 20, 'd': 30}) print(h1) # {'a': 99, 'b': 2, 'c': 3}
这样的目的是,让后面字典保持不变。例如第一个字典是私人配置,第二个字典是系统配置,操作只会影响个人配置,不会影响系统配置,这对于系统配置来说,是很重要的。
-
删除:删除键值对只会操作第一个字典。如果操作失败,会抛出异常。
pythonfrom collections import ChainMap h1 = {"a": 1, "b": 2, "c": 3} h2 = {"a": 10, "b": 20, "d": 30} h = ChainMap(h1, h2) # 删除操作只会对第一个字典进行操作,因为保存的是引用,因此,本质上是原字典执行的删除操作 del h["a"] print(h) # ChainMap({'b': 2, 'c': 3}, {'a': 10, 'b': 20, 'd': 30}) print(h1) # {'b': 2, 'c': 3} del h["a"] # 抛出异常,因为只会对第一个字典进行操作,在一个字典中删除不存在的key抛出异常。(不会对后续字典进行操作)
这样的目的是,让后面字典保持不变。例如第一个字典是私人配置,第二个字典是系统配置,操作只会影响个人配置,不会影响系统配置,这对于系统配置来说,是很重要的。
其他属性与操作
-
maps
属性:底层保存各个字典的列表。可以直接对该属性进行操作,实质是对原字典进行操作pythonfrom collections import ChainMap h1 = {"a": 1, "b": 2, "c": 3} h2 = {"a": 10, "b": 20, "d": 30} h = ChainMap(h1, h2) print(h.maps) # [{'a': 1, 'b': 2, 'c': 3}, {'a': 10, 'b': 20, 'd': 30}] # 使用该属性更改字典 h.maps[0]["a"] = 123 # 本质是改变原字典 print(h1) # {'a': 123, 'b': 2, 'c': 3}
-
new_child(m=None, **kwargs)
方法:返回一个新的 ChainMap,字典m
位于第一位,其他位于后面,保存的是引用。如果没有指定m
,相当于传入了一个空字典。调用d.new_child()
等价于ChainMap({}, *d.maps)
。如果指定了任何关键字参数kwargs
,它会更新所传入的字典。pythonfrom collections import ChainMap h1 = {"a": 1, "b": 2, "c": 3} h2 = {"a": 10, "b": 20, "d": 30} h = ChainMap(h1, h2) # 传入的字典位于最前,传入的kwargs更新传入的字典 hh = h.new_child({"a":-1}, b=10) # ChainMap({'a': -1, 'b': 10}, {'a': 1, 'b': 2, 'c': 3}, {'a': 10, 'b': 20, 'd': 30}) print(hh)
-
parents
属性:返回一个新的 ChainMap 对象,该对象等价于原对象去除了第一个字典。一个d.parents
等价于ChainMap(*d.maps[1:])
。pythonfrom collections import ChainMap h1 = {"a": 1, "b": 2, "c": 3} h2 = {"a": 10, "b": 20, "d": 30} h = ChainMap(h1, h2) hh = h.parents print(hh) # ChainMap({'a': 10, 'b': 20, 'd': 30})