Python 3 map字典更新方法到其他字典列表

Python 3 map dictionary update method to a list of other dictionaries

在 Python 2 中,我可以执行以下操作:

>> d = {'a':1}
>> extras = [{'b':2}, {'c':4}]
>> map(d.update, extras)
>> d['c']
>> 4

在Python 3中得到一个KeyError:

>> d = {'a':1}
>> extras = [{'b':2}, {'c':4}]
>> map(d.update, extras)
>> d['c']
>> KeyError: 'c'

我想在 Python 3 中实现与 Python 2 相同的行为。

我知道 Python 3 中的 map 将 return 一个迭代器(惰性求值等等),必须迭代它才能更新字典。

我原以为 d['c'] 键查找会以某种方式触发映射迭代,但事实并非如此。

是否有一种 pythonic 方法可以在不编写 for 循环的情况下实现这种行为, 与地图相比,我发现它很冗长。

我想到了使用列表理解:

>> d = {'a':1}
>> extras = [{'b':2}, {'c':4}]
>> [x for x in map(d.update, extras)]
>> d['c']
>> 4

但它看起来不像pythonic。

如您所见,Python 3 中的 map 创建了一个迭代器,它(本身)不会导致任何 update 发生:

>>> d = {'a': 1}
>>> extras = [{'b':2}, {'c':4}]
>>> map(d.update, extras)
<map object at 0x105d73c18>
>>> d
{'a': 1}

要强制对 map 进行全面评估,您可以将其显式传递给 list

>>> list(map(d.update, extras))
[None, None]
>>> d
{'a': 1, 'b': 2, 'c': 4}

然而,正如 What's new in Python 3 的相关部分所说:

Particularly tricky is map() invoked for the side effects of the function; the correct transformation is to use a regular for loop (since creating a list would just be wasteful).

在你的情况下,这看起来像:

for extra in extras:
    d.update(extra)

这不会导致不必要的列表 None

@jonrsharpe 的解释清楚地解释了问题在 Python 3 中,您可以使用 collections.ChainMap 来完成此类任务:

>>> from collections import ChainMap
>>> chain=ChainMap(d, *extras)
>>> chain
ChainMap({'a': 1}, {'b': 2}, {'c': 4})
>>> chain['c']
4

但请注意,如果有重复键,将使用 第一个 映射中的值。

阅读更多关于使用 ChainMap 的优势:What is the purpose of collections.ChainMap?