在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将返回一个迭代器(lazy evaluation and whatnot),必须迭代才能更新字典。
我假设d['c']
键查找会以某种方式触发地图迭代,但事实并非如此。
有没有pythonic方法来实现这种行为而无需编写for循环, 与地图相比,我发现它是冗长的。
我想过使用列表推导:
>> d = {'a':1}
>> extras = [{'b':2}, {'c':4}]
>> [x for x in map(d.update, extras)]
>> d['c']
>> 4
但它似乎并不像pythonic。
答案 0 :(得分:7)
正如您所注意到的,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的相关部分所说:
特别棘手的是
map()
被调用的副作用 功能;正确的转换是使用常规for
循环 (因为创建列表只会浪费)。
在您的情况下,这看起来像:
for extra in extras:
d.update(extra)
不会产生None
的不必要列表。
答案 1 :(得分: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
但请注意,如果存在重复键,则会使用 first 映射中的值。
详细了解使用ChainMap的优势:What is the purpose of collections.ChainMap?