未加星标

字典对象的 Pythonic 用法

字体大小 | |
[开发(python) 所属分类 开发(python) | 发布者 店小二05 | 时间 2017 | 作者 红领巾 ] 0人收藏点击收藏

字典对象在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及以下版本使用

dict((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 用法

本文开发(python)相关术语:python基础教程 python多线程 web开发工程师 软件开发工程师 软件开发流程

主题: 数据结构Python数据大数据4G
分页:12
转载请注明
本文标题:字典对象的 Pythonic 用法
本站链接:http://www.codesec.net/view/520155.html
分享请点击:


1.凡CodeSecTeam转载的文章,均出自其它媒体或其他官网介绍,目的在于传递更多的信息,并不代表本站赞同其观点和其真实性负责;
2.转载的文章仅代表原创作者观点,与本站无关。其原创性以及文中陈述文字和内容未经本站证实,本站对该文以及其中全部或者部分内容、文字的真实性、完整性、及时性,不作出任何保证或承若;
3.如本站转载稿涉及版权等问题,请作者及时联系本站,我们会及时处理。
登录后可拥有收藏文章、关注作者等权限...
技术大类 技术大类 | 开发(python) | 评论(0) | 阅读(36)