前言Collection是一种专门的容器数据类型(ContainerDatatype),可以替代Python通用的内置容器,如dict、list、set、tuple。容器是一种特殊用途的对象,可用于存储不同的对象。它提供了一种访问包含的对象并迭代它们的方法。Python提供了实现容器数据类型的集合模块。在系列章节中,我们将学习集合模块中的不同类型的集合,包括:ChainMapCounterDequeDefaultDictNamedTupleOrderedDictUserDictUserListUserString下面分别介绍一下这些容器类型——ChainMap。理解ChainMapPython提供的ChainMap类(简称链表类)是一个类字典(dict)的类,用于快速链接许多映射,以便将它们作为一个单元进行处理。它通常比创建新字典并运行多个update()调用要快得多。其语法格式如下:xchainMap=collections.ChainMap(*maps)说明:语法格式中的collections为导入的完整模块名称。如果模块是这样导入的:importcollectionsascts,语法可以修改为:classcts.ChainMap(*maps),或者fuzzyimport:fromcollectionsimportChainMap,修改为:ChainMap(*maps)。ChainMap可以将多个字典或其他映射组合在一起以创建一个可更新的视图(字典列表)。如果未指定映射,则会提供一个空字典,以便新的ChainMap始终至少有一个映射可用。链表的底层映射存储在列表中。该列表是公开的,可以使用maps属性访问或更新。除了maps属性之外,链映射没有其他新的扩展状态。ChainMap通过引用合并底层映射。因此,如果其中一个底层地图得到更新,这些更改也将反映在ChainMap中。Chainmap支持所有常用的字典(dict)方法。此外,还有一个用于创建新子上下文的方法的maps属性,属性maps可用于访问除第一个地图之外的所有地图-地图是一个列表。对应于从第一次搜索到最后一次搜索排序的用户可更新映射列表。它是唯一可以修改以更改搜索哪些映射的存储状态。这样的列表应该总是包含至少一个映射。我们看下面这个简单的例子,代码清单如下:运行程序输出如下:ChainMap({'one':1,'two':2},{'a':'A','b':'B'})[{'one':1,'two':2},{'a':'A','b':'B'}]在上面的列表中,我们使用了两个定义ChainMap对象(chain_map)的字典。然后我们打印出ChainMap对象和maps属性。正如您在输出中看到的,结果是这些字典的构成视图。访问ChainMap键值我们可以使用keys()和values()方法访问ChainMap键和值。代码示例如下:上述代码的输出为:KeysView(ChainMap({'one':1,'two':2},{'a':'A','b':'B'}))ValuesView(ChainMap({'one':1,'two':2},{'a':'A','b':'B'}))如程序输出所示,结果chain_map.keys()的结果是一个KeysView(键视图),chain_map.values()的结果是一个ValuesView(值视图)。这两种视图类型的内置类都是可迭代对象,可以分别遍历对应的键名和值对象。例如:输出结果为:key=a,value=Akey=b,value=Bkey=one,value=1key=two,value=2链映射中包含的值为:A;B;1;2;结合代码和输出结果,很容易理解链式映射就是将多个映射(map有多种实现,字典是其中一种)打包成一个映射,即链式映射,然后像访问字典。例如,像字典一样访问一个键的值:print(chain_map['b']),就是通过键名:chain_map['one']访问ChainMap底层字典中单项的值。添加新映射到ChainMap一个ChainMap可以包含任意数量的字典。我们使用内置的new_child()方法向ChainMap添加新字典。new_child()方法返回一个新的ChainMap,其中包含新映射,后跟当前实例中的所有映射。这里需要注意的一点是,新添加的字典会放在ChainMap的开头。看一个例子:运行程序,输入结果如下:Old:ChainMap({'one':1,'two':2},{'a':'A','b':'B'})新:ChainMap({'x':0,'y':1},{'one':1,'two':2},{'a':'A','b':'B'})这里要注意的是,用链表的new_child()方法添加新字典后,不会改变原来的链表,返回一个新的ChainMap对象。此外,如果您修改链接地图中包含的映射或字典,这些更改也会反映在链接地图对象中。另外,实践中要注意:如果根据字典操作添加新的键值对,该键值对会被添加到链表中包含的第一个映射中,如:new_chain_map['X']='未知'。自己试试吧。如果包含的地图具有相同的密钥怎么办?在底层,链式地图主要是将多个字典或地图打包成一个地图集中运行。如果函数的字典具有相同的键怎么办?我们看一个例子:程序运行输出如下:ChainMap({'id':21001,'country':'大秦','emperor':'嬴政'},{'name':'李靖','country':'大唐','title':'元帅'})大秦('name','李靖')('country','大秦')('title','元帅')('id',21001)('emperor','嬴政')显然,当同一个字典条目出现在链接映射中时,只读取第一个,以第一个为准,当你更新一个键的值时,它只更新了第一张图内容的键值。如果你想一次更新所有映射中同一个键的值怎么办?你可以自定义一个ChainMap的子类来实现它,或者定义一个update方法。因为ChainMap中有一个属性maps保存着完整的映射关系,所以可以根据这个属性完成同一个key的一次性更新。这里有一个简单的方法来实现多个映射中同一个键的更新。示例代码如下:当然你可以写的复杂一些以满足更多的需求,也可以一次性实现多个map中同一个key的值。自己试试吧。本文小结本文主要介绍Python集合模块中的链式映射容器ChainMap的使用,可以将多个字典封装到一个对象中进行操作。同时需要注意的是,映射只是对原始字典的引用。当您修改原始字典时,相应的更改不会反映在链映射中。同时,在向ChainMap中添加新的键值对时,会添加到第一个包含的映射对象中。
