本文转载自:http://www.pythoner.com/13.html

Python中将两个字典进行合并操作,是一个比较常见的问题。本文将介绍几种实现两个字典合并的方案,并对其进行比较。

对于这个问题,比较直观的想法是将两个字典做相加操作,赋值给结果字典,其代码为:

方法一:

  1. dictMerged1 = dict( dict1.items() + dict2.items() )

  然而,该方法合并时所用时间较长,效率更高的代码为:

方法二:

  1. dictMerged2 = dict( dict1, **dict2 )

  这种方法使用的是dict()工厂方法(Python2.2以上版本)。如果输入参数是另一个字典(此处为dict1),则调用该工厂方法时会从dict1中复制内容生成新的字典。该工厂方法从Python2.3版本开始,允许接受字典或关键字参数字典进行调用。但应当注意,对于这种调用方式,dict()最多只接受一个参数(或者说是一组name=value的可变长参数),而不会再接受另一个字典。因此直观上的简单使用dict1与dict2两个参数的方法会提示如下错误:

  1. >>> dictMerged = dict( dict1, dict2 )
  2. Traceback (most recent call last):
  3. File "<stdin>", line 1, in <module>
  4. TypeError: dict expected at most 1 arguments, got 2

  

这也就是我们看到上面的方法2中使用的是**dict2的原因。熟悉C的朋友应当注意,在这里*的意思并不代表指针,这是Python中可变长函数参数的写法(关于可变长函数参数的相关知识见下文)。在这里,**的意思是基于字典的可变长函数参数。

方法2执行的是如同下面方法3中的代码,即先将dict1拷贝给dictMerged,在执行update()操作:

  1. dictMerged3 = dict1.copy()
  2. dictMerged3.update( dict2 )

  

对于第一步的复制操作而言,这种使用内建方法copy()的复制方式,和方法2中的复制结果是一样的,但根据《Core Python Programming (2nd edition)》一书中7.3.2节所述,从已存在字典中生成新字典的方式dictNew = dict( dictOld )较内建方法dictNew = dictOld.copy()会慢一些,因此书中推荐使用copy()方法。

因此,从这几种方式看来,方法3的效率最高,并且代码也比较易读。

Python可变长度的函数参数

在编程的过程中,我们可能会遇到函数参数个数不固定的情况。这时就需要使用可变长度的函数参数来实现我们的功能。在Python中,有两种变长参数,分别是元组(非关键字参数)和字典(关键字参数)。其调用方式是:func( *tuple_grp_nonkw_args, **dict_grp_kw_args ),下面将详细介绍这两种变长参数。

1.元组变长参数

当函数调用中包括一个元组变长参数*tuple_grp_nonkw_args时,除去前面固定位置参数和关键字参数的其余参数将按顺序插入一个元组进行访问,这和C语言中的varargs的功能相同。

假设有这样一个函数(其中,positional_arg是位置固定的标准调用参数,keyword_arg是关键字参数):

示例:

  1. def foo( positional_arg, keyword_arg='default', *tuple_arg ):
  2. print "positional arg: ", positional_arg
  3. print "keyword_arg: ", keyword_arg
  4. for each_additional_arg in tuple_arg:
  5. print "additional_arg: ", each_additional_arg

  我们使用一些示例来了解它是怎么工作的:

  1. >>> foo(1)
  2. positional arg: 1
  3. keyword_arg: default
  4.  
  5. >>> foo(1, 2)
  6. positional arg: 1
  7. keyword_arg: 2
  8.  
  9. >>> foo(1, 2, 3)
  10. positional arg: 1
  11. keyword_arg: 2
  12. additional_arg: 3
  1. >>> foo(1,2,3,4,5,6)
  2. positional arg: 1
  3. keyword_arg: 2
  4. additional_arg: 3
  5. additional_arg: 4
  6. additional_arg: 5
  7. additional_arg: 6
  8. >>> foo(1,2,(3,4,5,6))
  9. positional arg: 1
  10. keyword_arg: 2
  11. additional_arg: (3, 4, 5, 6)

  

  

2.字典变长参数

既然Python中允许关键字参数,那么也应该有一种方式实现关键字的变长参数,这就是字典变长参数。

字典变长参数中,额外的关键字参数被放入了一个字典进行使用。字典中,键为参数名,值为相应的参数值。其表示方式是放在函数参数最后的**开头的参数,如**dict_grp_kw_args。(需要注意的是,**被重载以不与幂运算混淆。)

以下是一个字典变长参数的示例函数:

  1. def foo( positional_arg, keyword_arg='default', **dict_arg ):
  2. print "positional arg: ", positional_arg
  3. print "keyword_arg: ", keyword_arg
  4. for each_dict_arg in dict_arg.keys():
  5. print "dict_arg: %s=>%s" % ( each_dict_arg, str( dict_arg[each_dict_arg] ) )

  下面是一段演示结果:

  1. >>> foo(1, 2, a="b")
  2. positional arg: 1
  3. keyword_arg: 2
  4. dict_arg: a=>b

  

3.注意

函数调用的完整表达形式为:
func( positional_args, keyword_args, *tuple_grp_nonkw_args, **dict_grp_kw_args )

在使用的过程中,所有参数都是可选的,但应当注意的是:上面四种参数的位置是不可调换的!

4.扩展:C语言中的变长参数

作为一个学艺不精的人,之前一直不知道C语言中也是有可变参数的,直到在《Pointers on C》(中译名:《C和指针》,人民邮电出版社)中看到相关内容(7.6节)。

4.1 stdarg宏

在C语言中,可变参数是通过stdarg宏来实现的,它是标准库的一部分。这个头文件声明了一个类型va_list和三个宏va_startva_argva_end。我们可以声明一个类型为va_list的变量,与三个宏配合使用,访问参数的值。

下面是一个计算多个数值平均值的示例函数:

  1. //下面是一个计算多个数值平均值的示例函数:
  2. #include <stdarg.h>
  3.  
  4. float avg( int n, ... ) {
  5. va_list var_arg;
  6. float sum = 0;
  7.  
  8. // 准备访问变长参数
  9. va_start( var_arg, n );
  10.  
  11. // 添加取自变长参数列表的值
  12. for ( i = 0; i < n; i += 1) {
  13. sum += va_arg( var_arg, int );
  14. }
  15.  
  16. // 完成处理变长参数
  17. va_end( var_arg);
  18.  
  19. return sum / n;
  20. }

  

其中,函数参数中的...作为参数占位符,代表数量和类型不可知的一些参数。

函数中声明了一个va_list类型的变量var_arg用于访问参数列表的不确定部分。这个变量通过调用va_start进行初始化,其中,第一个参数是va_list变量的名字,第二个参数是占位符前最后一个有名字的参数。初始化过程将var_arg变量指向可变参数中的第一个参数。

va_list的使用中,包括两个参数,第一个参数是va_list变量,第二个参数是下一个参数的类型。本例中假设输入数据均为整型,因此均设置为int,而在一些情况下,下一个参数的类型会由之前的参数来决定。

最后,调用va_end结束变长参数的访问。

4.2 限制与注意事项

可变参数是从头到尾进行访问的,即可以在访问了数个参数之后结束,但不可以一开始就访问中间的参数。

另外,由于可变参数部分没有原型,因此作为可变参数传递给函数的值都做了缺省的函数类型提升。

从va_start的调用可以看出,如果使用可变参数必须有至少一个确定的参数,否则无法使用va_start。

对于这些宏,有两个基本限制:其一,无法判断实际存在的参数数量;其二,不能判断参数类型。

还需要注意的是,一旦在使用中写错下一个参数的类型,后果可能不堪设想。

【转载】Python中如何高效实现两个字典合并,三种方法比较。的更多相关文章

  1. Linux中让终端输入变为非阻塞的三种方法

    介绍 在linux下每打开一个终端,系统自动的就打开了三个文件,它们的文件描述符分别为0,1,2,功能分别是"标准输入"."标准输出"和"标准错误输出 ...

  2. python面对对象编程------3:写集合类的三种方法

    写一个集合类的三种方法:wrap,extend,invent 一:包装一个集合类 class Deck: def __init__( self ): self._cards = [card6(r+1, ...

  3. 【机器学习算法-python实现】协同过滤(cf)的三种方法实现

    (转载请注明出处:http://blog.csdn.net/buptgshengod) 1.背景       协同过滤(collaborative filtering)是推荐系统经常使用的一种方法.c ...

  4. c语言实现两数交换的三种方法

    实现变量的值互相交换的三种不同方法 方法一:利用第三个变量来实现数值的交换 int tmp; tmp = a; a = b; b = tmp; 此方法直观,简易.不易出错,推荐使用 方法二:利用两个变 ...

  5. python中打印金字塔和九九乘法表的几种方法

    # 打印九九乘法表for i in range(1,10): for j in range(1,i+1): # x=i*j # print(i,'*',j,'=',x,end=' ') print(' ...

  6. vuex中怎么把‘库’中的状态对象赋值给内部对象(三种方法)

    一.通过computed的计算属性直接赋值 import store from '@/store/store' export default{ name: 'count', data(){ retur ...

  7. java交换两个值的三种方法 经典

    1.中间变量(在开发中常用) int c=a; a=b; b=c; System.out.println("a的值: "+a+" b的值: "+b); 2.按位 ...

  8. Struts2 在Action中获取request、session、servletContext的三种方法

    首页message.jsp: <body> ${requestScope.req }<br/> ${applicationScope.app }<br/> ${se ...

  9. 关于SQLServer数据库中字段值为NULL,取出来该字段放在DataTable中,判断datatable中该字段值是否为NULL的三种方法

    1. DataTable dt;                               //假设字段为name, dt已经保存了数据dt.rows[0]["name"] == ...

随机推荐

  1. RTC硬件时钟设置修改【转】

    转自:http://os.chinaunix.net/a2008/0526/981/000000981211.shtml 这两天一直在做i2c设备驱动的理解,所以很少更新文章. 由于对于表计来说,RT ...

  2. ubuntu下如何查看用户登录及系统授权相关信息【转】

    转自:http://www.tuicool.com/articles/ia67Bj 如何在ubuntu下查看相关用户登录历史,进行系统的日志跟踪和分析,以便发现系统登录问题,进行安全策略防护呢?ubu ...

  3. sysfs - 用于导出内核对象(kobject)的文件系统

    sysfs - _The_ filesystem for exporting kernel objects.sysfs - 用于导出内核对象(kobject)的文件系统Patrick Mochel & ...

  4. [NYIST15]括号匹配(二)(区间dp)

    题目链接:http://acm.nyist.edu.cn/JudgeOnline/problem.php?pid=15 经典区间dp,首先枚举区间的大小和该区间的左边界,这时右边界也可计算出来.首先初 ...

  5. 爬虫技术(四)-- 简单爬虫抓取示例(附c#代码)

    这是我的第一个爬虫代码...算是一份测试版的代码.大牛大神别喷... 通过给定一个初始的地址startPiont然后对网页进行捕捉,然后通过正则表达式对网址进行匹配. List<string&g ...

  6. Scrum Agile

    Scrum Agile 迭代式增量软件开发,敏捷开发,源于丰田汽车的制造流程. HMC测试流程: 1.hmc改配置 2.上ui验证 3.还原hmm(有的需要,有的不需要) 4.addReferal,在 ...

  7. 【笨嘴拙舌WINDOWS】GDI对象之位图

    GDI对象在windows中可以描述成为一次绘画操作时可使用的抽象工具.包括(画笔.画刷.字体.区域.调色板.位图等) GDI对象里的对象概念和在编程领域中面向对象编程的对象概念是不一样的! GDI对 ...

  8. Home Server

    今天分享一个作品--HomeServer,一个基于云存储理念的集家庭数据存储.共享.管理及远程访问为一体的家用存储设备.通俗的讲,就是一个家庭数据银行,为家庭的数据提供专业.安全.便捷.持久.全天候的 ...

  9. 采用RPC方式和document方式 开发Axis2的WebService客户端

    import javax.xml.namespace.QName; import org.apache.axiom.om.OMAbstractFactory; import org.apache.ax ...

  10. ElasticSearch在Azure中的集群配置和Auto-Scale

    最近在项目中ElasticSearch的使用越来越多,最新的项目中要求ES使用集群,在啥都不知道的情况下弄了两天后,终于搞定,因此写个笔记记录下. 1.首先我们需要创建一个Virtual networ ...