Python中的defaultdict模块和namedtuple模块的简单入门指南


Posted in Python onApril 01, 2015

在Python中有一些内置的数据类型,比如int, str, list, tuple, dict等。Python的collections模块在这些内置数据类型的基础上,提供了几个额外的数据类型:namedtuple, defaultdict, deque, Counter, OrderedDict等,其中defaultdict和namedtuple是两个很实用的扩展类型。defaultdict继承自dict,namedtuple继承自tuple。
一、defaultdict

 1. 简介

在使用Python原生的数据结构dict的时候,如果用d[key]这样的方式访问,当指定的key不存在时,是会抛出KeyError异常的。但是,如果使用defaultdict,只要你传入一个默认的工厂方法,那么请求一个不存在的key时, 便会调用这个工厂方法使用其结果来作为这个key的默认值。

defaultdict在使用的时候需要传一个工厂函数(function_factory),defaultdict(function_factory)会构建一个类似dict的对象,该对象具有默认值,默认值通过调用工厂函数生成。

2. 示例

下面给一个defaultdict的使用示例:
 

In [1]: from collections import defaultdict
 
In [2]: s = [('xiaoming', 99), ('wu', 69), ('zhangsan', 80), ('lisi', 96), ('wu', 100), ('yuan', 98), ('xiaoming', 89)]
 
In [3]: d = defaultdict(list)
 
In [4]: for k, v in s:
  ...:   d[k].append(v)
  ...:  
 
In [5]: d
Out[5]: defaultdict(<type 'list'>, {'lisi': [96], 'xiaoming': [99, 89], 'yuan': [98], 'zhangsan': [80], 'wu': [69, 100]})
 
In [6]: for k, v in d.items():
  ...:   print '%s: %s' % (k, v)
  ...:  
lisi: [96]
xiaoming: [99, 89]
yuan: [98]
zhangsan: [80]
wu: [69, 100]

对Python比较熟悉的同学可以发现defaultdict(list)的用法和dict.setdefault(key, [])比较类似,上述代码使用setdefault实现如下:
 

s = [('xiaoming', 99), ('wu', 69), ('zhangsan', 80), ('lisi', 96), ('wu', 100), ('yuan', 98), ('xiaoming', 89)]
d = {}
 
for k, v in s:
  d.setdefault(k, []).append(v)

3. 原理

从以上的例子中,我们可以基本了defaultdict的用法,下面我们可以通过help(defaultdict)了解一下defaultdict的原理。通过Python console打印出的help信息来看,我们可以发现defaultdict具有默认值主要是通过__missing__方法实现的,如果工厂函数不为None,则通过工厂方法返回默认值,具体如下:
 

def __missing__(self, key):
  # Called by __getitem__ for missing key
  if self.default_factory is None:
    raise KeyError((key,))
  self[key] = value = self.default_factory()
  return value

从上面的说明中,我们可以发现一下几个需要注意的地方:

a). __missing__方法是在调用__getitem__方法发现KEY不存在时才调用的,所以,defaultdict也只会在使用d[key]或者d.__getitem__(key)的时候才会生成默认值;如果使用d.get(key)是不会返回默认值的,会出现KeyError;

b). defaultdict主要是通过__missing__方法实现,所以,我们也可以通过实现该方法来生成自己的defaultdict,代码入下:

In [1]: class MyDefaultDict(dict):
  ...:   def __missing__(self, key):
  ...:     self[key] = 'default'
  ...:     return 'default'
  ...:  
 
In [2]: my_default_dict = MyDefaultDict()
 
In [3]: my_default_dict
Out[3]: {}
 
In [4]: print my_default_dict['test']
default
 
In [5]: my_default_dict
Out[5]: {'test': 'default'}

4. 版本

defaultdict是在Python 2.5之后才加入的功能,在旧版本的Python中是不支持这个功能的,不过,知道了它的原理,我们可以自己实现一个defaultdict。

# http://code.activestate.com/recipes/523034/
try:
  from collections import defaultdict
except:
  class defaultdict(dict):
 
    def __init__(self, default_factory=None, *a, **kw):
      if (default_factory is not None and
        not hasattr(default_factory, '__call__')):
        raise TypeError('first argument must be callable')
      dict.__init__(self, *a, **kw)
      self.default_factory = default_factory
 
    def __getitem__(self, key):
      try:
        return dict.__getitem__(self, key)
      except KeyError:
        return self.__missing__(key)
 
    def __missing__(self, key):
      if self.default_factory is None:
        raise KeyError(key)
      self[key] = value = self.default_factory()
      return value
 
    def __reduce__(self):
      if self.default_factory is None:
        args = tuple()
      else:
        args = self.default_factory,
      return type(self), args, None, None, self.items()
 
    def copy(self):
      return self.__copy__()
 
    def __copy__(self):
      return type(self)(self.default_factory, self)
 
    def __deepcopy__(self, memo):
      import copy
      return type(self)(self.default_factory, copy.deepcopy(self.items()))
 
    def __repr__(self):
      return 'defaultdict(%s, %s)' % (self.default_factory, dict.__repr__(self))

二、namedtuple

namedtuple主要用来产生可以使用名称来访问元素的数据对象,通常用来增强代码的可读性,在访问一些tuple类型的数据时尤其好用。其实,在大部分时候你应该使用namedtuple替代tuple,这样可以让你的代码更容易读懂,更加pythonic。举个例子:

from collections import namedtuple
 
# 变量名和namedtuple中的第一个参数一般保持一致,但也可以不一样
Student = namedtuple('Student', 'id name score')
# 或者 Student = namedtuple('Student', ['id', 'name', 'score'])
 
students = [(1, 'Wu', 90), (2, 'Xing', 89), (3, 'Yuan', 98), (4, 'Wang', 95)]
 
for s in students:
  stu = Student._make(s)
  print stu
 
# Output:
# Student(id=1, name='Wu', score=90)
# Student(id=2, name='Xing', score=89)
# Student(id=3, name='Yuan', score=98)
# Student(id=4, name='Wang', score=95)

在上面的例子中,Student就是一个namedtuple,它和tuple的使用方法一样,可以通过index直接取,而且是只读的。这种方式比tuple容易理解多了,可以很清楚的知道每个值代表的含义。

Python 相关文章推荐
python两种遍历字典(dict)的方法比较
May 29 Python
python中global与nonlocal比较
Nov 21 Python
python实现中文分词FMM算法实例
Jul 10 Python
Python使用os模块和fileinput模块来操作文件目录
Jan 19 Python
为Python的Tornado框架配置使用Jinja2模板引擎的方法
Jun 30 Python
Python selenium实现微博自动登录的示例代码
May 16 Python
浅谈python新式类和旧式类区别
Apr 26 Python
Python实现的远程文件自动打包并下载功能示例
Jul 12 Python
Python批量将图片灰度化的实现代码
Apr 11 Python
Python实现一个优先级队列的方法
Jul 31 Python
vscode+PyQt5安装详解步骤
Aug 12 Python
关于探究python中sys.argv时遇到的问题详解
Feb 23 Python
Python进行数据科学工作的简单入门教程
Apr 01 #Python
10个易被忽视但应掌握的Python基本用法
Apr 01 #Python
用Python制作检测Linux运行信息的工具的教程
Apr 01 #Python
用Python的pandas框架操作Excel文件中的数据教程
Mar 31 #Python
Python实现国外赌场热门游戏Craps(双骰子)
Mar 31 #Python
通过代码实例展示Python中列表生成式的用法
Mar 31 #Python
使用Python实现一个简单的项目监控
Mar 31 #Python
You might like
php的大小写敏感问题整理
2011/12/29 PHP
探讨PHP使用eAccelerator的API开发详解
2013/06/09 PHP
PHP封装的分页类与简单用法示例
2019/02/25 PHP
JAVASCRIPT HashTable
2007/01/22 Javascript
javascript 导出数据到Excel(处理table中的元素)
2009/12/18 Javascript
JQuery 动态扩展对象之另类视角
2010/05/25 Javascript
JavaScript判断DOM何时加载完毕的技巧
2012/11/11 Javascript
Jquery 改变radio/checkbox选中状态,获取选中的值(示例代码)
2013/12/12 Javascript
jQuery仿淘宝网产品品牌隐藏与显示效果
2015/09/01 Javascript
jQuery+CSS实现一个侧滑导航菜单代码
2016/05/09 Javascript
基于JS实现横线提示输入验证码随验证码输入消失(js验证码的实现)
2016/10/27 Javascript
基于vuejs+webpack的日期选择插件
2020/05/21 Javascript
微信小程序 配置文件详细介绍
2016/12/14 Javascript
angularjs项目的页面跳转如何实现(5种方法)
2017/05/25 Javascript
JS+HTML5 FileReader实现文件上传前本地预览功能
2020/03/27 Javascript
浅谈vue项目可以从哪些方面进行优化
2018/05/05 Javascript
解决淘宝cnpm 安装后cnpm不是内部或外部命令的问题
2018/05/17 Javascript
vue项目中使用scss的方法步骤
2019/05/16 Javascript
ES6小技巧之代替lodash
2019/06/07 Javascript
如何使用CSS3+JQuery实现悬浮墙式菜单
2019/06/18 jQuery
layui表格分页 记录勾选的实例
2019/09/02 Javascript
Layui事件监听的实现(表单和数据表格)
2019/10/17 Javascript
Vue学习之组件用法实例详解
2020/01/06 Javascript
[44:43]完美世界DOTA2联赛决赛日 FTD vs GXR 第一场 11.08
2020/11/11 DOTA
Centos5.x下升级python到python2.7版本教程
2015/02/14 Python
django 修改server端口号的方法
2018/05/14 Python
Python实现获取邮箱内容并解析的方法示例
2018/06/16 Python
对Python协程之异步同步的区别详解
2019/02/19 Python
Python 捕获代码中所有异常的方法
2020/08/03 Python
Pycharm-community-2020.2.3 社区版安装教程图文详解
2020/12/08 Python
外贸销售员求职的自我评价
2013/11/23 职场文书
工作室成员个人发展规划范文
2014/01/24 职场文书
社区活动策划方案
2014/08/21 职场文书
小学教师师德整改措施
2014/09/29 职场文书
贴吧吧主申请感言
2015/08/03 职场文书
go语言中fallthrough的用法说明
2021/05/06 Golang