Python 合并词典的几种方式,你有没有为某个Python程序搭建过配置系统?搭建这种系统的常见做法是采用具有默认配置选项的数据结构,然后从用户输入或其他配置来源中有选择地覆盖默认值。
我经常使用字典作为底层数据结构来表示配置中的键和值,因此需要一种方法来将配置的默认值和用户覆盖的值合并到单个字典中,作为最终配置值。
通俗来说,有时需要将两个或更多字典合并为一个字典,让生成的字典包含各字典的键和值。
本节将介绍几种合并字典的方法,先通过一个简单的例子入手。假设有下面这两个字典:
>>> xs = {'a': 1, 'b': 2}
>>> ys = {'b': 3, 'c': 4}
现在要创建一个新的字典zs
,其中包含xs
和ys
中的所有键和值。如果仔细阅读示例,会发现字符串'b'
在这两个字典中都作为键出现了,因此还需要考虑如何处理重复键的冲突问题。
在Python中合并多个字典的经典办法是使用内置字典的update()
方法:
>>> zs = {}
>>> zs.update(xs)
>>> zs.update(ys)
你可能对update()
感到好奇,其基本实现相当于遍历右侧字典中的所有项,并将每个键值对添加到左侧字典中,在此过程中会用新的值覆盖现有键对应的值:
def update(dict1, dict2):
for key, value in dict2.items():
dict1[key] = value
函数会产生一个新的字典zs
,其中包含了在xs
和ys
中定义的键:
>>> zs
>>> {'c': 4, 'a': 1, 'b': 3}
从中可以看出,调用update()
的顺序决定了冲突的解决方式。新字典以最后更新的字典为主,比如xs
和ys
中都含有的键'b'
现在与ys
(第二个字典)的值3
关联起来。
这个update()
调用可以随意扩展,因此能够合并任意数量的字典。这个办法实用且易读,Python 2和Python 3都可用。
另一个在Python 2和Python 3中合并字典的办法是结合内置的dict()
与**
操作符来“拆包”对象:
>>> zs = dict(xs, **ys)
>>> zs
{'a': 1, 'c': 4, 'b': 3}
但与多次调用update()
一样,这种方式只适用于合并两个字典,无法一次合并多个字典。
从Python 3.5开始,**
操作符变得更加灵活。因此在Python 3.5+中还有另外一种更漂亮的方法来合并任意数量的字典:
>>> zs = {**xs, **ys}
该表达式的结果与依次调用update()
完全相同。键和值按照从左到右的顺序设置,所以解决冲突的方式也相同,都是右侧优先。ys
中的值覆盖xs
中相同键下已有的值。查看合并后的字典可以清楚地看到这一点:
>>> zs
>>> {'c': 4, 'a': 1, 'b': 3}
我个人喜欢这种简洁但依然具有可读性的新语法。在冗长和简洁之间总是会有一个平衡点,最大限度地让代码既可读又可维护。
因此如果使用的是Python 3,则建议使用这种新语法。**
操作符还有一个优点是执行起来比依次调用update()
更快。
关键要点
-
在Python 3.5及更高版本中,使用
**
操作符可在一个表达式内合并多个字典对象,现有的键从左向右依次覆盖。 -
若想兼容旧版本的Python,则需要用到内置字典的
update()
方法。