【转载】Python中如何高效实现两个字典合并,三种方法比较。

本文转载自: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
2
3
4

dictMerged
=
dict
( dict1, dict2 )

Traceback (most recent call last):

File
"<stdin>"
, line
1
,
in
<module>

TypeError:
dict
expected at most
1
arguments, got
2

这也就是我们看到上面的方法2中使用的是dict2的原因。熟悉C的朋友应当注意,在这里的意思并不代表指针,这是Python中可变长函数参数的写法(关于可变长函数参数的相关知识见下文)。在这里,的意思是基于字典的可变长函数参数。*
方法2执行的是如同下面方法3中的代码,即先将dict1拷贝给dictMerged,在执行update()
操作:
1
2

dictMerged3

dict1.copy()

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
2
3
4
5

def
foo( positional_arg, keyword_arg
=
'default'
,

tuple_arg ):

print
"positional arg: "
, positional_arg

print
"keyword_arg: "
, keyword_arg

for
each_additional_arg
in
tuple_arg:

print
"additional_arg: "
, each_additional_arg

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

foo(
1
)

positional arg:
1

keyword_arg: default

foo(
1
,
2
)

positional arg:
1

keyword_arg:
2

foo(
1
,
2
,
3
)

positional arg:
1

keyword_arg:
2

additional_arg:
3


1
2
3
4
5
6
7
8
9
10
11

foo(
1
,
2
,
3
,
4
,
5
,
6
)

positional arg:
1

keyword_arg:
2

additional_arg:
3

additional_arg:
4

additional_arg:
5

additional_arg:
6

foo(
1
,
2
,(
3
,
4
,
5
,
6
))

positional arg:
1

keyword_arg:
2

additional_arg: (
3
,
4
,
5
,
6
)

2.字典变长参数
既然Python中允许关键字参数,那么也应该有一种方式实现关键字的变长参数,这就是字典变长参数。
字典变长参数中,额外的关键字参数被放入了一个字典进行使用。字典中,键为参数名,值为相应的参数值。其表示方式是放在函数参数最后的开头的参数,如dict_grp_kw_args。(需要注意的是,**被重载以不与幂运算混淆。)
以下是一个字典变长参数的示例函数:
1
2
3
4
5

def
foo( positional_arg, keyword_arg
=
'default'
,

dict_arg ):

print
"positional arg: "
, positional_arg

print
"keyword_arg: "
, keyword_arg

for
each_dict_arg
in
dict_arg.keys():

print
"dict_arg: %s=>%s"
%
( each_dict_arg,
str
( dict_arg[each_dict_arg] ) )

下面是一段演示结果:
1
2
3
4

foo(
1
,
2
, a
=
"b"
)

positional arg:
1

keyword_arg:
2

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_start
、va_arg
、va_end
。我们可以声明一个类型为va_list的变量,与三个宏配合使用,访问参数的值。
下面是一个计算多个数值平均值的示例函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

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

include <stdarg.h>

float
avg(
int
n, ... ) {

va_list
var_arg;

float
sum = 0;

// 准备访问变长参数

va_start
( var_arg, n );

// 添加取自变长参数列表的值

for
( i = 0; i < n; i += 1) {

sum +=
va_arg
( var_arg,
int
);

}

// 完成处理变长参数

va_end
( var_arg);

return
sum / n;

}

其中,函数参数中的...
作为参数占位符,代表数量和类型不可知的一些参数。
函数中声明了一个va_list类型的变量var_arg用于访问参数列表的不确定部分。这个变量通过调用va_start进行初始化,其中,第一个参数是va_list变量的名字,第二个参数是占位符前最后一个有名字的参数。初始化过程将var_arg变量指向可变参数中的第一个参数。
va_list的使用中,包括两个参数,第一个参数是va_list变量,第二个参数是下一个参数的类型。本例中假设输入数据均为整型,因此均设置为int,而在一些情况下,下一个参数的类型会由之前的参数来决定。
最后,调用va_end结束变长参数的访问。
4.2 限制与注意事项
可变参数是从头到尾进行访问的,即可以在访问了数个参数之后结束,但不可以一开始就访问中间的参数。
另外,由于可变参数部分没有原型,因此作为可变参数传递给函数的值都做了缺省的函数类型提升。
从va_start的调用可以看出,如果使用可变参数必须有至少一个确定的参数,否则无法使用va_start。
对于这些宏,有两个基本限制:其一,无法判断实际存在的参数数量;其二,不能判断参数类型。
还需要注意的是,一旦在使用中写错下一个参数的类型,后果可能不堪设想。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,277评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,689评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,624评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,356评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,402评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,292评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,135评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,992评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,429评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,636评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,785评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,492评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,092评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,723评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,858评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,891评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,713评论 2 354

推荐阅读更多精彩内容