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装饰器验证配置文件示例
Feb 24 Python
Python的Flask框架应用程序实现使用QQ账号登录的方法
Jun 07 Python
浅谈Python NLP入门教程
Dec 25 Python
Python模块搜索路径代码详解
Jan 29 Python
python中实现将多个print输出合成一个数组
Apr 19 Python
Django 使用logging打印日志的实例
Apr 28 Python
python实现对csv文件的列的内容读取
Jul 04 Python
pygame游戏之旅 添加icon和bgm音效的方法
Nov 21 Python
Python3.5内置模块之time与datetime模块用法实例分析
Apr 27 Python
python3文件复制、延迟文件复制任务的实现方法
Sep 02 Python
selenium 多窗口切换的实现(windows)
Jan 18 Python
Python安装与卸载流程详细步骤(图解)
Feb 20 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
phplock(php进程锁) v1.0 beta1
2009/11/24 PHP
php通过session防url攻击方法
2014/12/10 PHP
在云虚拟主机部署thinkphp5项目的步骤详解
2017/12/21 PHP
PHP聚合式迭代器接口IteratorAggregate用法分析
2017/12/28 PHP
PHP中抽象类,接口功能、定义方法示例
2019/02/26 PHP
PHP远程连接oracle数据库操作实现方法图文详解
2019/04/11 PHP
jQuery布局插件UI Layout简介及使用方法
2013/04/03 Javascript
让人蛋疼的JavaScript语法特性
2014/09/30 Javascript
jquery中EasyUI实现异步树
2015/03/01 Javascript
jquery 重写 ajax提交并判断权限后 使用load方法报错解决方法
2016/01/19 Javascript
js获取当前日期时间及其它日期操作汇总
2016/03/08 Javascript
BootStrap的JS插件之轮播效果案例详解
2016/05/16 Javascript
jquery pagination分页插件使用详解(后台struts2)
2017/01/22 Javascript
BootStrap的双日历时间控件使用
2017/07/25 Javascript
在 Linux/Unix 中不重启 Vim 而重新加载 .vimrc 文件的流程
2018/03/21 Javascript
JavaScript获取用户所在城市及地理位置
2018/04/21 Javascript
Node.JS在命令行中检查Chrome浏览器是否安装并打开指定网址
2019/05/21 Javascript
使用Vue生成动态表单
2019/11/26 Javascript
微信小程序中网络请求缓存的解决方法
2019/12/29 Javascript
PyQt5每天必学之带有标签的复选框
2018/04/19 Python
python实时监控cpu小工具
2018/06/21 Python
Python设计模式之策略模式实例详解
2019/01/21 Python
centos6.5安装python3.7.1之后无法使用pip的解决方案
2019/02/14 Python
Python 实现OpenCV格式和PIL.Image格式互转
2020/01/09 Python
Python新手学习标准库模块命名
2020/05/29 Python
Web前端绘制0.5像素的几种方法
2017/08/11 HTML / CSS
css3媒体查询中device-width和width的区别详解
2020/03/27 HTML / CSS
英国袜子店:Sock Shop
2017/01/11 全球购物
可以在一个PHP文件里面include另外一个PHP文件两次吗
2015/05/22 面试题
有针对性的求职自荐信
2013/11/14 职场文书
寒假实习自荐信
2014/01/26 职场文书
教师个人剖析材料
2014/02/05 职场文书
入党积极分子自我鉴定
2014/02/18 职场文书
贪污受贿检讨书范文
2014/11/19 职场文书
幼师大班个人总结
2015/02/13 职场文书
「魔导具师妲莉亚永不妥协~从今天开始的自由职人生活~」1、2卷发售宣传CM公开
2022/03/21 日漫