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实现Tab自动补全和历史命令管理的方法
Mar 12 Python
Flask框架的学习指南之制作简单blog系统
Nov 20 Python
Python读写及备份oracle数据库操作示例
May 17 Python
基于python实现名片管理系统
Nov 30 Python
解决python xx.py文件点击完之后一闪而过的问题
Jun 24 Python
python将excel转换为csv的代码方法总结
Jul 03 Python
在pycharm中实现删除bookmark
Feb 14 Python
Python新手如何理解循环加载模块
May 29 Python
QT5 Designer 打不开的问题及解决方法
Aug 20 Python
Python3如何在服务器打印资产信息
Aug 27 Python
基于python实现坦克大战游戏
Oct 27 Python
python 调用Google翻译接口的方法
Dec 09 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
mysql建立外键
2006/11/25 PHP
PHP取进制余数函数代码
2012/01/19 PHP
深入mysql_fetch_row()与mysql_fetch_array()的区别详解
2013/06/05 PHP
PHP的pcntl多进程用法实例
2015/03/19 PHP
PHP数据库连接mysql与mysqli对比分析
2016/01/04 PHP
如何使用php等比例缩放图片
2016/10/12 PHP
javascript firefox不显示本地预览图片问题的解决方法
2008/11/12 Javascript
IE6 fixed的完美解决方案
2011/03/31 Javascript
一个JavaScript去除字符串末尾的空白实例代码
2014/09/22 Javascript
js实现文章文字大小字号功能完整实例
2014/11/01 Javascript
jquery实现简洁文件上传表单样式
2015/11/02 Javascript
JavaScript Math.round() 方法
2015/12/18 Javascript
JavaScript事件代理和委托详解
2016/04/08 Javascript
用jQuery实现圆点图片轮播效果
2017/03/19 Javascript
AngularJS实现的回到顶部指令功能实例
2017/05/17 Javascript
JS设计模式之命令模式概念与用法分析
2018/02/06 Javascript
在 Vue 项目中引入 tinymce 富文本编辑器的完整代码
2018/05/04 Javascript
js实现自动播放匀速轮播图
2020/02/06 Javascript
浅谈element中InfiniteScroll按需引入的一点注意事项
2020/06/05 Javascript
Python中下划线的使用方法
2015/03/27 Python
python实现从网络下载文件并获得文件大小及类型的方法
2015/04/28 Python
Python3使用requests包抓取并保存网页源码的方法
2016/03/15 Python
使用python接入微信聊天机器人
2020/03/31 Python
使用jupyter Nodebook查看函数或方法的参数以及使用情况
2020/04/14 Python
Python析构函数__del__定义原理解析
2020/11/20 Python
几个解决兼容IE6\7\8不支持html5标签的几个方法
2013/01/07 HTML / CSS
RentCars.com巴西:汽车租赁网站
2016/08/22 全球购物
电子商务系毕业生自荐信
2014/05/29 职场文书
风雨哈佛路观后感
2015/06/03 职场文书
烛光里的微笑观后感
2015/06/17 职场文书
2015年网络舆情工作总结
2015/07/24 职场文书
详解Python 3.10 中的新功能和变化
2021/04/28 Python
解析高可用Redis服务架构分析与搭建方案
2021/06/20 Redis
Java 在生活中的 10 大应用
2021/11/02 Java/Android
python工具dtreeviz决策树可视化和模型可解释性
2022/03/03 Python
postgresql之greenplum字符串去重拼接方式
2023/05/08 PostgreSQL