Python“扩展”字典


462

扩展词典与另一本词典的最佳方法是什么?例如:

>>> a = { "a" : 1, "b" : 2 }
>>> b = { "c" : 3, "d" : 4 }
>>> a
{'a': 1, 'b': 2}
>>> b
{'c': 3, 'd': 4}

我正在寻找任何操作来获得此避免for循环:

{ "a" : 1, "b" : 2, "c" : 3, "d" : 4 }

我希望做这样的事情:

a.extend(b)  # This does not work

25
我知道要使用列表[],然后我认为可能是对其他人有用,而不是其他人;-)
FerranB

Answers:


694

6
阅读文档后,您将了解为什么会有“更新”而不是“扩展”。
乔治2014年

58
请记住,update()直接修改字典并返回None。
e18r 2015年

5
但是,如果您只想使用尚未定义的值扩展dict (即不覆盖现有值)怎么办?例如,更新字典{"a":2, "b":3}用字典{"b":4, "c":5},以字典{"a":2, "b":3,"c":5}?当然,可以update()通过移动一些东西来使用,但是如果只用一行就可以完成,那就更好了……
Nearoo

17
@Nearoo-只需更新相反的方式即可;而不是x.update(y)[使用y覆盖x值],而是使用y.update(x)[使用x覆盖y值],并使用y作为您选择的字典进行进一步的操作
jonathanl

请记住,update静默覆盖现有条目。即,任何值都将b覆盖a重叠键的值。
CGFoX

186

这个封闭的问题中的一颗美丽的宝石:

“单一方式”,既不改变输入命令,也不改变

basket = dict(basket_one, **basket_two)

了解什么是**basket_two(在**)指这里

如果发生冲突,来自的项目basket_two将覆盖来自的项目basket_one。就像一线书一样,这是很容易理解和透明的,并且我不反对在任何时候都可以方便地使用由其他两种方法混合而成的字典(实际上,任何理解它的读者都会得到很好的服务)顺便这促使他或她对学习dict**形式;-)。因此,例如,使用如下:

x = mungesomedict(dict(adict, **anotherdict))

在我的代码中相当频繁地出现。

最初由Alex Martelli提交

注意:在Python 3中,只有在basket_two中的每个键都是a的情况下,这才起作用string


3
的文档dict很容易找到,但**比较棘手(关键字是kwargs)。这是一个很好的解释:saltycrane.com/blog/2008/01/…–
johndodo

4
它可以用于通过单个命令生成第二个变量,而basket_one.update(<dict>)顾名思义,它可以更新现有字典(或克隆的字典)。
弗林斯

2
请注意,在Python 3中,参数名称以及的键**anotherdict必须是字符串。
Petr Viktorin 2014年

感谢@johndodo-我已将您的建议整合到帖子中。
汤姆·莱斯

1
一个很好的功能替代已接受的答案。如果您需要直接使用新组合的字典,则此方法是理想的。(另请参阅@ e18r对已接受答案的评论)。
chinnychinchin

45

您是否尝试过将字典理解与字典映射一起使用:

a = {'a': 1, 'b': 2}
b = {'c': 3, 'd': 4}

c = {**a, **b}
# c = {"a": 1, "b": 2, "c": 3, "d": 4}

另一种方法是通过使用dict(iterable,** kwarg)

c = dict(a, **b)
# c = {'a': 1, 'b': 2, 'c': 3, 'd': 4}

在Python 3.9中,您可以使用union | 算子

# use the merging operator |
c = a | b
# c = {'a': 1, 'b': 2, 'c': 3, 'd': 4}

5
仅供参考:这不是Python 2.7中的有效语法
Asav Patel

2
这种语法是相当新的(Python 3.5)
pianoJames

24
a.update(b)

将键和值从b添加到a,如果键已经存在,则覆盖。


17

正如其他人提到的那样,a.update(b)对于某些命令而言ab它将达到您在问题中所要求的结果。但是,我想指出的是,我多次看到extend映射/设置对象的方法希望在语法中a.extend(b)a的值不应被b的值覆盖。a.update(b)会覆盖a的值,因此不是的理想选择extend

请注意,某些语言将这种方法称为defaultsinject,因为可以将其视为将b的值(可能是一组默认值)注入字典中而不覆盖可能已经存在的值的方法。

当然,您可以简单地注意到与a.extend(b)几乎相同b.update(a); a=b。要删除分配,您可以这样进行:

def extend(a,b):
    """Create a new dictionary with a's properties extended by b,
    without overwriting.

    >>> extend({'a':1,'b':2},{'b':3,'c':4})
    {'a': 1, 'c': 4, 'b': 2}
    """
    return dict(b,**a)

感谢Tom Leys提出的巧妙想法,它使用的无副作用dict构造函数extend


1

您还可以使用python 3.3中引入的python的collections.Chainmap

from collections import Chainmap
c = Chainmap(a, b)
c['a'] # returns 1

根据您的用例,这有一些可能的优点。这里将对它们进行更详细的说明,但我将做一个简要概述:

  • 链图仅使用词典的视图,因此实际上没有数据被复制。这样可以加快链接速度(但查找速度较慢)
  • 实际上没有键被覆盖,因此,如有必要,您可以知道数据是来自a还是来自b。

这主要使其对于诸如配置字典之类的事情有用。


0

如果您需要将其作为Class,则可以使用dict扩展它并使用update方法:

Class a(dict):
  # some stuff
  self.update(b)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.