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网络编程学习笔记(五):socket的一些补充
Jun 09 Python
Python利用ElementTree模块处理XML的方法详解
Aug 31 Python
Python中Numpy ndarray的使用详解
May 24 Python
PyQt QCombobox设置行高的方法
Jun 20 Python
numpy.ndarray 实现对特定行或列取值
Dec 05 Python
keras实现theano和tensorflow训练的模型相互转换
Jun 19 Python
python 指定源路径来解决import问题的操作
Mar 04 Python
python 中 .py文件 转 .pyd文件的操作
Mar 04 Python
Python文件的操作示例的详细讲解
Apr 08 Python
Python生成九宫格图片的示例代码
Apr 14 Python
Python入门之基础语法详解
May 11 Python
Python标准库pathlib操作目录和文件
Nov 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
php目录操作函数之获取目录与文件的类型
2010/12/29 PHP
PHP分页详细讲解(有实例)
2013/10/30 PHP
PHP四大安全策略
2014/03/12 PHP
php表单请求获得数据求和示例
2014/05/15 PHP
php自定义hash函数实例
2015/05/05 PHP
php通过各种函数判断0和空
2020/07/04 PHP
XAMPP升级PHP版本实现步骤解析
2020/09/04 PHP
关于jQuery $.isNumeric vs. $.isNaN vs. isNaN
2013/04/15 Javascript
jqueyr判断checkbox组的选中(示例代码)
2013/11/08 Javascript
jQuery中ready事件用法实例
2015/01/19 Javascript
JavaScript知识点总结(十)之this关键字
2016/05/31 Javascript
jQuery插件简单学习实例教程
2016/07/01 Javascript
jQuery排序插件tableSorter使用方法
2017/02/10 Javascript
[js高手之路]图解javascript的原型(prototype)对象,原型链实例
2017/08/28 Javascript
Nodejs实现文件上传的示例代码
2017/09/26 NodeJs
javaScript日期工具类DateUtils详解
2017/12/08 Javascript
vue2.0在没有dev-server.js下的本地数据配置方法
2018/02/23 Javascript
详解auto-vue-file:一个自动创建vue组件的包
2019/04/26 Javascript
javascript实现前端成语点击验证优化
2020/06/24 Javascript
js实现星星海特效的示例
2020/09/28 Javascript
[13:38]2015国际邀请赛中国战队出征仪式
2015/05/29 DOTA
Python 列表list使用介绍
2014/11/30 Python
浅析Python中元祖、列表和字典的区别
2016/08/17 Python
对numpy中array和asarray的区别详解
2018/04/17 Python
Django实现列表页商品数据返回教程
2020/04/03 Python
Pycharm导入anaconda环境的教程图解
2020/07/31 Python
办公室文秘自我评价
2013/09/21 职场文书
会计系个人求职信范文分享
2013/12/20 职场文书
一月红领巾广播稿
2014/02/11 职场文书
挂职自我鉴定
2014/02/26 职场文书
乡镇四风对照检查材料
2014/08/31 职场文书
我爱家乡演讲稿
2014/09/12 职场文书
领导班子党的群众路线对照检查材料
2014/09/25 职场文书
社区四风存在问题及整改措施
2014/10/26 职场文书
校本研修个人总结
2015/02/28 职场文书
2016国培研修心得体会
2016/01/08 职场文书