广告
返回顶部
首页 > 资讯 > 后端开发 > Python >Python中怎么实现字典合并操作
  • 594
分享到

Python中怎么实现字典合并操作

2023-06-16 14:06:06 594人浏览 八月长安

Python 官方文档:入门教程 => 点击学习

摘要

本篇文章给大家分享的是有关python中怎么实现字典合并操作,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。2.1 dict.updated1.update(d2) 确

本篇文章给大家分享的是有关python中怎么实现字典合并操作,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。

2.1 dict.update

d1.update(d2) 确实能合并两个字典,但它是在修改d1的基础上进行。如果我们想要合并成一个新的字典,没有一个直接使用表达式的方式,而需要借助临时变量进行:

e = d1.copy()  e.update(d2)

2.2 {**d1, **d2}

字典解包可以将两个字典合并为一个新的字典,但看起来有些丑陋,并且不能让人显而易见地看出这是在合并字典。

{**d1, **d2} 还会忽略映射类型,并始终返回字典类型。

2.3 collections.ChainMap

ChainMap 很少有人知道,它也可以用作合并字典。但和前面合并方式相反,在合并两个字典时,第一个字典的键会覆盖第二个字典的相同键。

此外,由于 ChainMap 是对入参字典的封装,这意味着写入 ChainMap 会修改原始字典:

>>> from collections import ChainMap  >>> d1 = {'a':1}  >>> d2 = {'a':2}  >>> merged = ChainMap(d1, d2)  >>> merged['a']     # d1['a'] 会覆盖 d2['a']  1  >>> merged['a'] = 3 # 实际等同于 d1['a'] = 3  >>> d1  {'a': 3}

2.4 dict(d1, **d2)

这是一种鲜为人知的合并字典的“巧妙方法”,但如果字典的键不是字符串,它就不能有效工作了:

>>> d1 = {'a': 1}  >>> d2 = {2: 2}  >>> dict(d1, **d2)  Traceback (most recent call last):    ...  TypeError: keyWords must be strings

三、原理

新操作符同 dict.update 方法的关系,就和列表连接(+)、扩展(+=)操作符同 list.extend 方法的关系一样。需要注意的是,这和集合中 |/|= 操作符同 set.update 的关系稍有不同。作者明确了允许就地运算符接受更广泛的类型(就像 list 那样)是一种更有用的设计,并且限制二进制操作符的操作数类型(就像 list 那样)将有助于避免由复杂的隐式类型转换引起的错误被吞掉。

>>> l1 = [1, 2]  >>> l1 + (3,) # 限制操作数的类型,不是列表就报错  Traceback (most recent call last)  ...  TypeError: can only concatenate list (not "tuple") to list  >>> l1 += (3,) # 允许就地运算符接受更广泛的类型(如元组)  >>> l1  [1, 2, 3]

当合并字典发生键冲突时,以最右边的值为准。这和现存的字典类似操作相符,比如:

{'a': 1, 'a': 2} # 2 覆盖 1  {**d, **e}       # e覆盖d中相同键所对应的值  d.update(e)      # e覆盖d中相同键所对应的值  d[k] = v         # v 覆盖原有值  {k: v for x in (d, e) for (k, v) in x.items()} # e覆盖d中相同键所对应的值

四、规范

字典合并会返回一个新字典,该字典由左操作数与右操作数合并而成,每个操作数必须是 dict(或 dict 子类的实例)。如果两个操作数中都出现一个键,则最后出现的值(即来自右侧操作数的值)将会覆盖:

>>> d = {'spam': 1, 'eggs': 2, 'cheese': 3}  >>> e = {'cheese': 'cheddar', 'aardvark': 'Ethel'}  >>> d | e  {'spam': 1, 'eggs': 2, 'cheese': 'cheddar', 'aardvark': 'Ethel'}  >>> e | d # 不符合交换律,左右互换操作数会得到不同的结果  {'aardvark': 'Ethel', 'spam': 1, 'eggs': 2, 'cheese': 3}

扩展赋值版本的就地操作:

>>> d |= e # 将 e 更新到 d 中  >>> d  {'spam': 1, 'eggs': 2, 'cheese': 'cheddar', 'aardvark': 'Ethel'}

扩展赋值的行为和字典的 update 方法完全一样,它还支持任何实现了映射协议(更确切地说是实现了 keys 和 __getitem__ 方法)或键值对迭代对象。所以:

>>> d | [('spam', 999)]   # “原理”章节中提到限制操作数的类型,不是字典或字典子类就报错  Traceback (most recent call last):    ...  TypeError: can only merge dict (not "list") to dict   >>> d |= [('spam', 999)]  # “原理”章节中提到允许就地运算符接受更广泛的类型,其行为和 update 一样,接受键值对迭代对象  >>> d  {'eggs': 2, 'cheese': 'cheddar', 'aardvark': 'Ethel', 'spam': 999}

五、主流观点

5.1 字典合并不符合交换律

合并是符合交换律的,但是字典联合却没有(d | e != e | d)。

回应

Python 中有过不符合交换律的合并先例:

>>> {0} | {False}  {0}  >>> {False} | {0}  {False}

上述结果虽然是相等的,但是本质是不同的。通常来说,a | b 和 b | a 并不相同。

5.2 字典合并并不高效

类似管道写法使用多次字典合并并不高效,比如 d | e | f | g | h 会创建和销毁三个临时映射。

回应

这种问题在序列级联时同样会出现。

序列级联的每一次合并都会使序列中的元素总数增加,最终会带来 O(N^2) 的性能开销。而字典合并有可能会有重复键,因此临时映射的大小并不会如此快速地增长。

正如我们很少将大量的列表或元组连接在一起一样,PEP的作者任务合并大量的字典也是少见情况。若是确实有这样的诉求,那么最好使用显式的循环和就地合并:

new = {}  for d in many_dicts:      new |= d

5.3 字典合并是有损的

字典合并可能会丢失数据(相同键的值可能消失),其他形式的合并并不会。

回应

作者并不觉得这种有损是一个问题。此外,dict.update 也会发生这种情况,但并不会丢弃键,这其实是符合预期的。只不过是现在使用的不是 update 而是 |。

如果从不可逆的角度考虑,其他类型的合并也是有损的。假设 a | b 的结果是365,那么 a 和 b 是多少却不得而知。

5.4 只有一种方法达到目的

字典合并不符合“Only One Way”的禅宗。

回应

其实并没有这样的禅宗。“Only One Way”起源于很早之前Perl社区对Python的诽谤。

5.5 超过一种方法达到目的

好吧,禅宗并没有说“Only One Way To Do It”。但是它明确禁止“超过一种方法达到目的”。

回应

并没有这样的禁止。Python 之禅仅表达了对“仅一种显而易见的方式”的偏爱。

There should be one-- and preferably only one --obvious way to do  it.

它的重点是应该有一种明显的方式达到目的。对于字典更新操作来说,我们可能希望至少执行两个不同的操作:

  •  就地更新字典:显而易见的方式是使用 update() 方法。如果此提案被接受,|= 扩展赋值操作符也将等效,但这是扩展赋值如何定义的副作用。选择哪种取决于使用者口味。

  •  合并两个现存的字典到新字典中:此提案中显而易见的方法是使用 | 合并操作符。

实际上,Python 里经常违反对“仅一种方式”的偏爱。例如,每个 for 循环都可以重写为 while 循环;每个 if 块都可以写为 if/else 块。列表、集合和字典推导都可以用生成器表达式代替。列表提供了不少于五种方法来实现级联:

  •  级联操作符:a + b

  •  就地级联操作符:a + = b

  •  切片分配:a[len(a):] = b

  •  序列解压缩:[*a, *b]

  •  扩展方法:a.extend(b)

我们不能太教条主义,不能因为它违反了“仅一种方式”就非常严格的拒绝有用的功能。

5.6 字典合并让代码更难理解

字典合并让人们更难理解代码的含义。为了解释该异议,而不是具体引用任何人的话:“在看到 spam | eggs,如果不知道 spam 和 eggs 是什么,根本就不知道这个表达式的作用”。

回应

这确实如此,即使没有该提案,| 操作符的现状也是如此:

  •  对于 int/bool 是按位或

  •  对于 set/forzenset 是并集

  •  还可能是任何其他的重载操作

添加字典合并看起来并不会让理解代码变得更困难。确定 spam 和 eggs 是映射类型并不比确定是集合还是整数要花更多的工作。其实良好的命名约定将会有助于改善情况:

flags |= WRITEABLE  # 可能就是数字的按位或  DO_NOT_RUN = WEEKENDS | HOLIDAYS  # 可能就是集合合并  settings = DEFAULT_SETTINGS | user_settings | workspace_settings  # 可能就是字典合并

5.7 参考下完整的集合API

字典和集合很相似,应该要支持集合所支持的操作符:|、&、^ 和 -。

回应

也许后续会有PEP来专门说明这些操作符如何用于字典。简单来说:

把集合的对称差集(^)操作用在字典上面是显而易见且自然。比如:

>>> d1 = {"spam": 1, "eggs": 2}  >>> d2 = {"ham": 3, "eggs": 4}

对于 d1 和 d2 对称差集,我们期望 d1 ^ d2 应该是 {"spam": 1, "ham": 3}

把集合的差集(-)操作用在字典上面也是显而易见和自然的。比如 d1 和 d2 的差集,我们期望:

  •  d1 - d2 为 {"spam": 1}

  •  d2 - d1 为 {"ham": 3}

把集合的交集(&)操作用在字典上面就有些问题了。虽然很容易确定两个字典中键的交集,但是如何处理键所对应的值就比较模糊。不难看出 d1 和 d2 的共同键是 eggs,如果我们遵循“后者胜出”的一致性原则,那么值就是 4。

六、已拒绝的观点

PEP 584 提案中罗列了很多已拒绝的观点,比如使用 + 来合并字典;在合并字典时也合并值类型为列表的值等等。这些观点都非常有意思,被拒绝的理由也同样有说服力。限于篇幅的原因不再进一步展开,感兴趣的可以阅读 https://www.python.org/dev/peps/pep-0584/#id34。

七、实现

7.1 纯 Python 实现

def __or__(self, other):      if not isinstance(other, dict):          return NotImplemented      new = dict(self)      new.update(other)      return new  def __ror__(self, other):      if not isinstance(other, dict):          return NotImplemented      new = dict(other)      new.update(self)      return new  def __ior__(self, other):      dict.update(self, other)      return self

纯 Python 实现并不复杂,我们只需让 dict 实现几个魔法方法:

  __or__ 和 __ror__ 魔法方法对应于 | 操作符,__or__ 表示对象在操作符左侧,__ror__ 表示对象在操作符右侧。实现就是根据左侧操作数生成一个新字典,再把右侧操作数更新到新字典中,并返回新字典。

  __ior__ 魔法方法对应于 |= 操作符,将右侧操作数更新到自身即可。

7.2 CPython 实现

CPython 中字典合并的详细实现可见此 PR:Https://GitHub.com/python/cpython/pull/12088/files 。

最核心的实现如下:

// 实现字典合并生成新字典的逻辑,对应于 | 操作符  static PyObject *  dict_or(PyObject *self, PyObject *other)  {      if (!PyDict_Check(self) || !PyDict_Check(other)) {          Py_RETURN_NOTIMPLEMENTED;      }      PyObject *new = PyDict_Copy(self);      if (new == NULL) {          return NULL;      }      if (dict_update_arg(new, other)) {          Py_DECREF(new); // 减少引用计数          return NULL;      }      return new;  }  // 实现字典就地合并逻辑,对应于 |= 操作符  static PyObject *  dict_ior(PyObject *self, PyObject *other)  {      if (dict_update_arg(self, other)) {          return NULL;      }      Py_INCREF(self); // 增加引用计数      return self;  }

以上就是Python中怎么实现字典合并操作,小编相信有部分知识点可能是我们日常工作会见到或用到的。希望你能通过这篇文章学到更多知识。更多详情敬请关注编程网Python频道。

--结束END--

本文标题: Python中怎么实现字典合并操作

本文链接: https://www.lsjlt.com/news/283981.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Python中怎么实现字典合并操作
    本篇文章给大家分享的是有关Python中怎么实现字典合并操作,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。2.1 dict.updated1.update(d2) 确...
    99+
    2023-06-16
  • Python中怎么合并字典
    本篇文章给大家分享的是有关Python中怎么合并字典,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。1. 最简单的原地更新字典对象内置了一个 update 方法,用于把...
    99+
    2023-06-16
  • python如何字典的合并操作
    这篇文章主要为大家展示了“python如何字典的合并操作”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“python如何字典的合并操作”这篇文章吧。字典的合并操作比如我们有两个字典,存放不同用户的...
    99+
    2023-06-27
  • python解释器怎么实现字典合并
    这篇“python解释器怎么实现字典合并”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“python解释器怎么实现字典合并”文...
    99+
    2023-06-30
  • python如何实现字典合并
    这篇文章将为大家详细讲解有关python如何实现字典合并,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。字典合并a = {'a': 1, 'b...
    99+
    2023-06-27
  • python字典合并操作符的示例分析
    这篇文章主要介绍了python字典合并操作符的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。python的五大特点是什么python的五大特点:1.简单易学,开发程序...
    99+
    2023-06-14
  • 怎么用Python合并两个字典
    这篇文章将为大家详细讲解有关怎么用Python合并两个字典,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。用Python合并两个字典在python中,我们可以合并两个字典,而无需任何特定方法。 下面的代码是...
    99+
    2023-06-27
  • 如何使用Python实现字典合并
    这篇文章给大家分享的是有关如何使用Python实现字典合并的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。1、用for循环把一个字典合并到另一个字典把a字典合并到b字典中,相当于用for循环遍历a字典,然后取出a字...
    99+
    2023-06-29
  • python中字典和集合的常用操作
    本篇内容主要讲解“python中字典和集合的常用操作”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“python中字典和集合的常用操作”吧!#字典:存多个值,key-value存取,取值速度快,k...
    99+
    2023-06-02
  • python解释器实现字典合并的方法
    这篇文章主要介绍python解释器实现字典合并的方法,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!python的数据类型有哪些python的数据类型:1. 数字类型,包括int(整型)、long(长整型)和float...
    99+
    2023-06-14
  • 详解Python实现字典合并的四种方法
    目录1、用for循环把一个字典合并到另一个字典2、用dict(b, **a)方法构造一个新字典3、用b.update(a)的方法,更新字典4、把字典转换成列表合并后,再转换...
    99+
    2022-11-13
  • python怎么将两个列表合并成字典
    可以使用zip()函数将两个列表合并成字典。zip()函数可以将两个列表中的元素一一对应地组合在一起。下面是一个例子:```pyth...
    99+
    2023-10-11
    python
  • python怎么用双星号语法合并字典
    这篇文章主要介绍了python怎么用双星号语法合并字典,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。用双星号语法合并字典** (Python 3.5+)这种语法是自Pytho...
    99+
    2023-06-27
  • JavaScript中怎么实现数组合并操作
    本篇文章为大家展示了JavaScript中怎么实现数组合并操作,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。让我们先考虑下面这情况:var a = [ 1, 2, ...
    99+
    2022-10-19
  • python中怎么实现字典排序
    python中怎么实现字典排序,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。<lo:  ="" j="lo&quo...
    99+
    2023-06-04
  • python怎么实现字典推导
    这篇文章给大家分享的是有关python怎么实现字典推导的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。字典推导>>> m = {x:...
    99+
    2022-10-19
  • python字典翻转怎么实现
    今天小编给大家分享的是python字典翻转怎么实现,相信很多人都不太了解,为了让大家更加了解,所以给大家总结了以下内容,一起往下看吧。一定会有所收获的哦。第1关 创建大学英语四级单词字典本关任务:编写一个能创建大学英语四级单词字典的小程序。...
    99+
    2023-08-03
  • python中字典的常见操作实例分析
    这篇文章主要介绍了python中字典的常见操作实例分析的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇python中字典的常见操作实例分析文章都会有所收获,下面我们一起来看看吧。python中字典的常见操作字典添...
    99+
    2023-07-02
  • PHP中怎么实现数组合并与拆分操作
    这篇文章给大家介绍PHP中怎么实现数组合并与拆分操作,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。PHP数组合并与拆分之array_merge_recursive()用法array_merge_recursive()可...
    99+
    2023-06-17
  • redis中怎么对Hash字典进行操作
    redis中怎么对Hash字典进行操作,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。1.Redis操作之Hash操作redis支持五大数据类型,只支持第一层,也...
    99+
    2023-06-20
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作