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 httplib,smtplib使用方法
Sep 06 Python
Python中多线程及程序锁浅析
Jan 21 Python
Python3实现的画图及加载图片动画效果示例
Jan 19 Python
Python中的并发处理之asyncio包使用的详解
Apr 03 Python
Python实现合并同一个文件夹下所有txt文件的方法示例
Apr 26 Python
PyQt QListWidget修改列表项item的行高方法
Jun 20 Python
python循环定时中断执行某一段程序的实例
Jun 29 Python
python实现树的深度优先遍历与广度优先遍历详解
Oct 26 Python
python 基于dlib库的人脸检测的实现
Nov 08 Python
TensorFlow 输出checkpoint 中的变量名与变量值方式
Feb 11 Python
利用python汇总统计多张Excel
Sep 22 Python
Python自动化办公Excel模块openpyxl原理及用法解析
Nov 05 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三维数组去重(示例代码)
2013/11/26 PHP
IIS6.0 开启Gzip方法及PHP Gzip函数分享
2014/06/08 PHP
php ImageMagick windows下安装教程
2015/01/26 PHP
CodeIgniter辅助之第三方类库third_party用法分析
2016/01/20 PHP
ThinkPHP框架里隐藏index.php
2016/04/12 PHP
Yii框架批量插入数据扩展类的简单实现方法
2017/05/23 PHP
ajax+php实现无刷新验证手机号的实例
2017/12/22 PHP
multiSteps 基于Jquery的多步骤滑动切换插件
2011/07/22 Javascript
JavaScript实现鼠标点击后层展开效果的方法
2015/05/13 Javascript
javascript用函数实现对象的方法
2015/05/14 Javascript
javascript封装简单实现方法
2015/08/11 Javascript
原生JavaScript实现瀑布流布局
2020/06/28 Javascript
javascript cookie的简单应用
2016/02/24 Javascript
实例详解display:none与visible:hidden的区别
2017/03/30 Javascript
vue.js中mint-ui框架的使用方法
2017/05/12 Javascript
Vue使用watch监听一个对象中的属性的实现方法
2019/05/10 Javascript
[04:19]完美世界携手游戏风云打造 卡尔工作室模型介绍篇
2013/04/24 DOTA
[06:33]3.19 DOTA2发布会 海涛、冷冷、2009见证希望
2014/03/21 DOTA
[03:55]显微镜下的DOTA2特别篇——430灰烬之灵神级操作
2014/06/24 DOTA
Python从Excel中读取日期一列的方法
2018/11/28 Python
pandas.read_csv参数详解(小结)
2019/06/21 Python
Python 类的魔法属性用法实例分析
2019/11/21 Python
Tensorflow的常用矩阵生成方式
2020/01/04 Python
Python hashlib常见摘要算法详解
2020/01/13 Python
Python unittest 自动识别并执行测试用例方式
2020/03/09 Python
Pandas之read_csv()读取文件跳过报错行的解决
2020/04/21 Python
解决pymysql cursor.fetchall() 获取不到数据的问题
2020/05/15 Python
运行python提示no module named sklearn的解决方法
2020/11/29 Python
详解appium自动化测试工具(monitor、uiautomatorviewer)
2021/01/27 Python
Internet体系结构
2014/12/21 面试题
MYSQL基础面试题
2012/05/13 面试题
日期和时间问题
2015/01/04 面试题
高三英语教学计划
2015/01/23 职场文书
2015年迎新晚会策划书
2015/07/16 职场文书
公文写作:新员工转正申请书范本3篇!
2019/08/07 职场文书
python 离散点图画法的实现
2022/04/01 Python