专业编程基础技术教程

网站首页 > 基础教程 正文

合并 Python 中的字典3个方法的区别与联系

ccvgpt 2025-01-07 11:09:12 基础教程 3 ℃

1、在 Python 中使用 | 操作符合并字典

首先,让我们讨论合并字典的最简单方法,这通常已经足够满足你的需求。

合并 Python 中的字典3个方法的区别与联系

以下是两个字典:

>>> context = {"language": "en", "timezone": "UTC"}
>>> more_context = {"title": "Home", "breadcrumbs": ["Home"]}

我们希望创建一个新的第三个字典,该字典将这两个字典的内容结合起来。这个新字典应包含两个初始字典中的所有键值对。

最简单的方法是使用管道操作符(|

>>> new_context = context | more_context

这会创建一个新的字典,其中包括了两个初始字典的所有项目:

>>> new_context
{'language': 'en', 'timezone': 'UTC', 'title': 'Home', 'breadcrumbs': ['Home']}

使用 | 操作符,本质上相当于创建一个新的空字典,然后通过遍历第一个字典和第二个字典中的所有项目,将它们添加到新字典中:

>>> new_context = {}
>>> for key, value in context.items():
...     new_context[key] = value
...
>>> for key, value in more_context.items():
...     new_context[key] = value
...
>>> new_context
{'language': 'en', 'timezone': 'UTC', 'title': 'Home', 'breadcrumbs': ['Home']}

2、使用 update 方法合并字典

如果我们希望直接在原字典上进行更新,该怎么办?

假设我们仍然使用前面的两个字典:

>>> context = {"language": "en", "timezone": "UTC"}
>>> more_context = {"title": "Home", "breadcrumbs": ["Home"]}

现在,希望将第一个字典(context)更新为同时包含第二个字典(more_context)中的所有项目。

我们可以通过遍历第二个字典,将每个键值对添加到第一个字典中:

>>> for key, value in more_context.items():
...     context[key] = value
...
>>> context
{'language': 'en', 'timezone': 'UTC', 'title': 'Home', 'breadcrumbs': ['Home']}

但是,字典的 update 方法可以替代我们完成这些工作:

>>> context.update(more_context)

update 方法接收一个字典,并修改调用该方法的字典,使其包含两个字典中的所有键值对。

另外,还可以使用管道操作符的增强赋值语句

>>> context |= more_context

这与字典的 update 方法功能相同,因此具体选择哪个方法取决于个人喜好。

3、使用 ** 合并字典

我们还可以使用 Python 的双星号(**)语法来合并字典:

>>> combined = {**context, **more_context}

这会创建一个新字典,与管道操作符(|)的效果相同。

不过,我认为 {**a, **b} 的可读性稍差于 a | b,所以在合并字典时,我通常优先选择管道操作符。4、| 和 ** 的区别

需要注意的是,管道操作符(|)与双星号(**)并不完全一样。

有时,a | b{**a, **b} 的结果会有所不同。

例如,如果你使用管道操作符与一个自定义的映射类型(例如 defaultdict)进行合并,返回的新字典会保留该自定义类型。

以下是两个 defaultdict 对象:

>>> from collections import defaultdict
>>> group1 = defaultdict(list)
>>> group1["giraffe"].append("Gerard")
>>> group2 = defaultdict(list)
>>> group2["ferret"].append("Francis")
>>> group1
defaultdict(<class 'list'>, {'giraffe': ['Gerard']})
>>> group2
defaultdict(<class 'list'>, {'ferret': ['Francis']})

如果使用管道操作符将这两个 defaultdict 对象合并,返回的将是一个 defaultdict 对象:

>>> group1 | group2
defaultdict(<class 'list'>, {'giraffe': ['Gerard'], 'ferret': ['Francis']})

而如果使用 ** 语法合并这两个字典,返回的将是一个普通的 dict 对象:

>>> {**group1, **group2}
{'giraffe': ['Gerard'], 'ferret': ['Francis']}

使用管道操作符(|)合并字典时,第一个字典的类型会决定最终合并结果的类型。而使用 ** 合并字典时,结果始终是一个 dict 对象。

因此,在某些情况下,如果需要接受任意字典类型,但需要返回一个内置的 dict 类型,** 语法会更合适。不过,大多数情况下,| 的行为更符合实际需求。

5、合并时如何处理重复键

如果合并的两个字典中存在重复的键,会发生什么?

例如,以下两个字典中都包含 title 键:

>>> context = {"language": "en", "timezone": "UTC", "title": "Welcome"}
>>> more_context = {"title": "Home", "breadcrumbs": ["Home"]}

与通过 for 循环进行合并一样,在合并的过程中,最后一个值会覆盖重复键对应的值。

因为 more_context 位于 context 之后,title 的值将会是 Home(而非 Welcome):

>>> context | more_context
{'language': 'en', 'timezone': 'UTC', 'title': 'Home', 'breadcrumbs': ['Home']}

如果我们希望采用其他行为,比如在处理重复键时选择较大的值,该如何操作?以下示例中,我们希望当键重复时,保留更大的价格:

>>> prices1 = {"premium": 29.99, "basic": 9.99, "pro": 49.99}
>>> prices2 = {"basic": 7.99, "pro": 39.99}

遗憾的是,目前没有直接的快捷方式完成此需求。

我们可以通过复制第一个字典,然后遍历第二个字典,检查每个键是否在新字典中,并使用 get 方法比较并更新值:

>>> merged = prices1.copy()
>>> for plan, price in prices2.items():
...     if price > merged.get(plan, 0):
...         merged[plan] = price
...
>>> merged
{'premium': 29.99, 'basic': 9.99, 'pro': 49.99}

6、管道操作符 | 执行字典的“并集”操作

通常,合并两个字典最简单的方法是使用管道操作符:

>>> context = {"language": "en", "timezone": "UTC"}
>>> more_context = {"title": "Home", "breadcrumbs": ["Home"]}
>>> context | more_context
{'language': 'en', 'timezone': 'UTC', 'title': 'Home', 'breadcrumbs': ['Home']}

那么,为什么 Python 使用管道操作符(|)来实现此操作,而不是加号操作符(+)呢?

>>> context + more_context
Traceback (most recent call last):
  File "<python-input-4>", line 1, in <module>
    context + more_context
    ~~~~~~~~^~~~~~~~~~~~~~
TypeError: unsupported operand type(s) for +: 'dict' and 'dict'

加号操作符用于连接序列[1],但序列连接与字典合并有所不同。

字典需要处理重复键的情况,而序列则不需要。

管道操作符之所以被选择,是因为它已经被用于集合(set)的合并操作:

>>> names = {"language", "timezone", "title"}
>>> more_names = {"title", "breadcrumbs"}
>>> names | more_names
{'language', 'timezone', 'breadcrumbs', 'title'}

管道操作符可以对集合进行“并集”操作。你可以将字典的合并类比为两个字典的并集操作

最近发表
标签列表