11

在 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 将返回一个迭代器(惰性求值之类的),必须对其进行迭代才能更新字典。

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

有没有一种 Pythonic 方法可以在不编写 for 循环的情况下实现这种行为,我发现它与 map 相比显得冗长。

我曾想过使用列表推导:

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

但这似乎不是pythonic。

4

2 回答 2

10

正如您所注意到的,map在 Python 3 中创建了一个迭代器,它(本身)不会导致任何updates 发生:

>>> 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}

但是,正如Python 3中的新增功能的相关部分所说:

map()对于函数的副作用调用特别棘手;正确的转换是使用常规for循环(因为创建列表只是浪费)。

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

for extra in extras:
    d.update(extra)

这不会导致不必要的None.

于 2015-05-02T09:07:33.657 回答
1

除了@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 的优势:collections.ChainMap 的目的是什么?

于 2015-05-02T09:10:49.970 回答