【问题标题】:Python "extend" for a dictionaryPython“扩展”字典
【发布时间】:2010-10-09 07:11:41
【问题描述】:

在避免使用for 循环的同时,用另一个字典扩展字典的最佳方法是什么?例如:

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

结果:

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

类似:

a.extend(b)  # This does not work

【问题讨论】:

  • 我知道lists [],那么我想可能是为其他人工作,而不是extrange ;-)
  • 这个问题不是唯一定义的,因为示例应该涵盖 a 和 b 有公共键的情况

标签: python dictionary


【解决方案1】:

【讨论】:

  • 请记住 update() 直接修改 dict 并返回 None。
  • 但是,如果您只想扩展 dict 并使用 已经定义的值(即不覆盖现有值)?例如,将 dict {"a":2, "b":3} 与 dict {"b":4, "c":5} 更新为 dict {"a":2, "b":3,"c":5}?当然可以通过移动一些东西来使用update(),但是如果它可以在一行中完成会更好......
  • @Nearoo - 以相反的方式简单地更新;而不是 x.update(y) [将用 y 覆盖 x 值],使用 y.update(x) [用 x 覆盖 y 值] 并使用 y 作为您选择的 dict 以进行进一步操作
  • 请记住,update 会默默地覆盖现有条目。即,b 中的任何值都会覆盖 a 中的值,以实现重叠键。
【解决方案2】:

this closed question 中的一颗美丽宝石:

“单线方式”,不改变任何输入字典,是

basket = dict(basket_one, **basket_two)

了解**basket_two (the **) means here 的内容。

如果发生冲突,来自basket_two 的项目将覆盖来自basket_one 的项目。就单行而言,这是非常易读和透明的,并且我不会因为任何时候使用它而感到内疚这促使他或她学习dict** 表格的方式;-)。因此,例如,使用如下:

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

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

最初由Alex Martelli提交

注意:在 Python 3 中,这只有在 basket_two 中的每个键都是 string 时才有效。

【讨论】:

  • dict 的文档很容易找到,而 ** 则比较复杂(关键字是 kwargs)。这是一个很好的解释:saltycrane.com/blog/2008/01/…
  • 这可用于通过单个命令生成第二个变量,而 basket_one.update(<dict>) 顾名思义,更新现有字典(或克隆字典)。
  • 请注意,在 Python 3 中,参数名称以及 **anotherdict 的键必须是字符串。
  • 感谢@johndodo - 我已将您的建议整合到帖子中。
  • 一个不错的功能替代已接受的答案。如果您需要直接使用新组合的 dict,则这种方法是可取的。 (另见@e18r 对已接受答案的评论)。
【解决方案3】:

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

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}

In Python 3.9 you can add two dict using union | operator

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

【讨论】:

  • 仅供参考:这不是 Python 2.7 中的有效语法
  • 这个语法是fairly new (Python 3.5)
  • a.update(b) 对我不起作用,{**a, **b} 对我有用。不知道为什么,但感谢替代解决方案。
【解决方案4】:
a.update(b)

b中的键和值添加到a,如果键已经有值,则覆盖。

【讨论】:

    【解决方案5】:

    正如其他人所提到的,a.update(b) 对于某些 dicts 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 为extend 使用无副作用的dict 构造函数的聪明想法。

    【讨论】:

    • 这正是我想要的。非常好。
    【解决方案6】:

    你也可以使用python 3.3中引入的pythoncollections.Chainmap

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

    这有一些可能的优势,具体取决于您的用例。 here 对它们进行了更详细的解释,但我将简要概述一下:

    • chainmap 仅使用字典的视图,因此实际上不会复制任何数据。这会导致更快的链接(但更慢的查找)
    • 实际上没有任何键被覆盖,因此,如有必要,您可以知道数据来自 a 还是 b。

    这主要使它对诸如配置字典之类的东西有用。

    【讨论】:

      【解决方案7】:

      请注意,自从 python3.9 引入了更简单的语法(联合运算符):

      d1 = {'a': 1}
      d2 = {'b': 2}
      
      extended_dict = d1 | d2
      >> {'a':1, 'b': 2}
      

      注意:如果第一个字典与第二个字典共享密钥,位置很重要!

      d1 = {'b': 1}
      d2 = {'b': 2}
      d1 | d2 
      >> {'b': 2} 
      

      Link 相关 PEP

      【讨论】:

        【解决方案8】:

        如果你需要它作为一个,你可以用dict扩展它并使用update方法:

        Class a(dict):
          # some stuff
          self.update(b)
        

        【讨论】:

          猜你喜欢
          • 2014-11-10
          • 2023-03-08
          • 2021-06-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-06-30
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多