字典对象的 Pythonic 用法(上篇)
字典对象在Python中作为最常用的数据结构之一,和数字、字符串、列表、元组并列为5大基本数据结构,字典中的元素通过键来存取,而非像列表一样通过偏移存取。笔者总结了字典的一些常用Pyhonic用法,这是字典的Pythonic用法的上篇
0. 使用 in/not in 检查 key 是否存在于字典
判断某个 key 是否存在于字典中时,一般初学者想到的方法是,先以列表的形式把字典所有键返回,再判断该key是否存在于键列表中:
dictionary = {}
keys = dictionary.keys()
for k in keys:
if key == k:
print True
break
更具Pythonic的用法是使用in关键字来判断 key 是否 存在于字典中:
if key in dictionary:
print True
else:
print False
1. 使用 setdefault() 初始化字典键值
使用字典的时候经常会遇到这样一种应用场景:动态更新字典,像如下代码,如果 key 不在 dictionary 中那么就添加它并把它对应的值初始为空列表 [] ,然后把元素 append 到空列表中:
dictionary = {}
if "key" not in dictionary:
dictionary["key"] = []
dictionary["key"].append("list_item")
尽管这段代码没有任何逻辑错误,但是我们可以使用setdefault来实现更Pyhonic的写法:
dictionary = {}
dictionary.setdefault("key", []).append("list_item")
字典调用 setdefault 方法时,首先检查 key 是否存在,如果存在该方法什么也不做,如果不存在 setdefault 就会创建该 key,并把第二个参数[]作为 key 对应的值。
2. 使用 defaultdict() 初始化字典
初始化一个字典时,如果初始情况下希望所有 key 对应的值都是某个默认的初始值,比如有一批用户的信用积分都初始为100,现在想给 a 用户增加10分
d = {}
if 'a' not in d:
d['a'] = 100
d['a'] += 10
同样这段代码也没任何问题,换成更pyhtonic的写法是:
from collections import defaultdict
d = defaultdict(lambda: 100)
d['a'] += 10
defaultdict 是位于 collections 模块下,它是 dict 类的子类,语法结构是:
class collections.defaultdict([default_factory[, ...]])
第一个参数default_factory是一个工厂方法,每次初始化某个键的时候将会被调用,value就是default_factory返回的值,剩下的参数和dict()函数接收的参数一样
3. 使用 iteritems() 迭代大数据
迭代大数据字典时,如果是使用 items() 方法,那么在迭代之前,迭代器迭代前需要把数据完整地加载到内存,这种方式不仅处理非常慢而且浪费内存,下面代码约占1.6G内存(为什么是1.6G?可以参考:
http://stackoverflow.com/questions/4279358/pythons-underlying-hash-data-structure-for-dictionaries)
d = {i: i * 2 for i in xrange(10000000)}
for key, value in d.items():
print("{0} = {1}".format(key, value))
而使用 iteritem() 方法替换 items() ,最终实现的效果一样,但是消耗的内存降低50%,为什么差距那么大呢?因为 items() 返回的是一个 list,list 在迭代的时候会预先把所有的元素加载到内存,而 iteritem() 返回的一个迭代器(iterators),迭代器在迭代的时候,迭代元素逐个的生成。
d = {i: i * 2 for i in xrange(10000000)}
for key, value in d.iteritem():
print("{0} = {1}".format(key, value))
4. 高效合并字典
普通方法
合并多个字典的时候可以用一行代码实现:
x = {'a': 1, 'b': 2}
y = {'b': 3, 'c': 4}
z = dict(x.items() + y.items())
这种写法看起来很Pythonic,但仔细分析的话,它的执行效率并不高,items()方法在python2.7中返回的是列表对象,两个列表相加得到一个新的列表,这样内存中存在3个列表对象,如果两个列表的大小都是1G,那么执行这段代码需要占用4G的空间来创建这个字典。此外这段代码在Python3中会报错,因为python3中items()返回的是dict_items对象,而不是列表。
>>> c = dict(a.items() + b.items())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'dict_items' and 'dict_items'
在python3中,你需要明确地强制转换成list对象:
z = dict(list(x.items()) + list(y.items()))
Pythonic方法
在Python3.5中提供了一种全新的Pythonic方法:
z = {**x, **y}
不过考虑到大部分系统还是基于Python2,所以一种更兼容的pythonic方法是:
z = x.copy()
z.update(y)
当然,你可以把它封装成一个函数:
def merge_dicts(*dict_args):
'''
可以接收1个或多个字典参数
'''
result = {}
for dictionary in dict_args:
result.update(dictionary)
return result
z = merge_dicts(a, b, c, d, e, f, g)
其他方法
还有其他方式来合并字典,但是性能不一定是最优的,比如: python2.7可以支持字典推导式
{k: v for d in dicts for k, v in d.items()}
python2.6及以下版本使用
{k: v for d in dicts for k, v in d.items()}
性能对比
import timeit
>>> min(timeit.repeat(lambda: {**x, **y})) # python3.5
0.4094954460160807
>>> min(timeit.repeat(lambda: merge_two_dicts(x, y)))
0.5726828575134277
>>> min(timeit.repeat(lambda: {k: v for d in (x, y) for k, v in d.items()} ))
1.163769006729126
>>> min(timeit.repeat(lambda: dict((k, v) for d in (x, y) for k, v in d.items())))
2.2345519065856934
直接使用python3.5中的{**x, **y}是最快的,使用update次之,用字典推导式相对来说是最慢的。
字典对象的 Pythonic 用法(上篇)的更多相关文章
- 字典对象的 Pythonic 用法(上篇:转载)
转载:https://mp.weixin.qq.com/s?timestamp=1498528588&src=3&ver=1&signature=DfFeOFPXy44ObCM ...
- Python成长之路第二篇(3)_字典的置函数用法
字典的置函数用法(字典dict字典中的key不可以重复) class dict(object): """ dict() -> new empty dictionar ...
- Objective-c 字典对象
oc 中的 NSDictionary 的作用同 java 中的字典类相同,提供了 “键-值”对的组合.比如,是用字典类实现对学生姓名和学号的存放,编号是一个键(唯一性),姓名是值.它的方法有: 下面通 ...
- VBS使用Scripting.Dictionary字典对象
Scripting.Dictionary是个很有用的组件,其创建了类似于Key索引对应Value值的字典对象,并且在其内部提供了快速索引访问的机制,可以让我们通过Key直接索引到指定的Value,比遍 ...
- python 基础学习(字典对象,set对象)
1.dict 字典对象 a.定义对象 d={'a':14,'b':12}b.通过key获取value d['a'] 方法1.判断key是否存在 if 'a' in d: d['a']方法2:通过用ge ...
- JavaScript中创建字典对象(dictionary)实例
这篇文章主要介绍了JavaScript中创建字典对象(dictionary)实例,本文直接给出了实现的源码,并给出了使用示例,需要的朋友可以参考下 对于JavaScript来说,其自身的Array对象 ...
- DOM Style样式对象的详细用法
DOM Style样式对象的详细用法 HTML Style样式比较复杂,相应访问.修改方法也有所差异.参考相关资料,整理如下. 典型Html文件如下,有三种定义方式. <head> ...
- python爬虫requests json与字典对象互相转换
import requests import json ''' json.loads(json_str) json字符串转换成字典 json.dumps(dict) 字典转换成json字符串 ''' ...
- 有一个字典对象,d = {'a':1,'b':2},请用尽量简洁的代码将d转换成{1: 'a', 2: 'b'}
题目:有一个字典对象,d = {'a':1,'b':2},请用尽量简洁的代码将d转换成{1: 'a', 2: 'b'} 第一种方法: d = {'a': 1, 'b': 2}d = {value: k ...
随机推荐
- 配置用户通过Telnet登录设备的身份认证(AAA本地认证)
背景信息 用户通过Telnet登录设备时,设备上必须配置验证方式,否则用户无法成功登录设备.设备支持不认证.密码认证和AAA认证三种用户界面的验证方式,其中AAA认证方式安全性最高. 采用AAA本地认 ...
- java垃圾回收 - 为什么要进行垃圾回收
1.为什么要进行垃圾回收: 在C++中,对象所占的内存在程序结束运行之前一直被占用,在明确释放之前不能分配给其它对象:而在Java中,当没有对象引用指向原先分配给某个对象 的内存时,该内存便 ...
- Android APK 反编译步骤
dex2jar和jd-gui工具下载,链接:http://yun.baidu.com/share/link?shareid=2888715259&uk=1377615098 解压APK文件得到 ...
- Unity3D for VR 学习(6): 再次温故知新-3D数学
一年前,系统学习过3D数学,并记录了一篇博客<C#程序员整理的Unity 3D笔记(十):Unity3D的位移.旋转的3D数学模型>. 一年后,再次温习之. 坐标系:Unity3D使用左手 ...
- BZOJ4197 [Noi2015]寿司晚宴 【状压dp】
题目链接 BZOJ4197 题解 两个人选的数都互质,意味着两个人选择了没有交集的质因子集合 容易想到将两个人所选的质因子集合作为状态\(dp\) \(n\)以内质数很多,但容易发现\(\sqrt{n ...
- mysql三-1:存储引擎
一 什么是存储引擎 mysql中建立的库===>文件夹 库中建立的表===>文件 现实生活中我们用来存储数据的文件有不同的类型,每种文件类型对应各自不同的处理机制:比如处理文本用txt类型 ...
- Canny边缘检测算法原理及其VC实现详解(一)
转自:http://blog.csdn.net/likezhaobin/article/details/6892176 图象的边缘是指图象局部区域亮度变化显著的部分,该区域的灰度剖面一般可以看作是一个 ...
- 图片虚拟目录--即图片保存在window硬盘上面
这个是图片保存在电脑的硬盘上面的图片上传设置,既不是在web工程中,也不是在专门的图片服务器中,下面是配置方法: r 这里的Document base 我们这里设置为F:\images 如果在浏览器访 ...
- sloop公共函数之添加信号,定时器及socket
1:添加信号 1.1 原型:sloop_handle sloop_register_signal(int sig, sloop_signal_handler handler, void * param ...
- python学习(十一)测试和调试
最近学习了python的错误处理和几种测试方法 1 try except 可以通过try except方式捕捉异常 try: print('try...') r = 10/0 print('resul ...