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实现提取文章摘要的方法
Apr 21 Python
Python 关于反射和类的特殊成员方法
Sep 14 Python
Python 多进程和数据传递的理解
Oct 09 Python
浅谈用Python实现一个大数据搜索引擎
Nov 28 Python
tensorflow获取变量维度信息
Mar 10 Python
python 返回列表中某个值的索引方法
Nov 07 Python
对python 多个分隔符split 的实例详解
Dec 20 Python
Python匿名函数及应用示例
Apr 09 Python
python 字符串追加实例
Jul 20 Python
Tensorflow设置显存自适应,显存比例的操作
Feb 03 Python
PyQt5.6+pycharm配置以及pyinstaller生成exe(小白教程)
Jun 02 Python
python中sqllite插入numpy数组到数据库的实现方法
Jun 21 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
php5中date()得出的时间为什么不是当前时间的解决方法
2008/06/30 PHP
php 设计模式之 工厂模式
2008/12/19 PHP
深入理解PHP原理之错误抑制与内嵌HTML分析
2011/05/02 PHP
php连接odbc数据源并保存与查询数据的方法
2014/12/24 PHP
Yii2.0框架模型多表关联查询示例
2019/07/18 PHP
用jQuery技术实现Tab页界面之二
2009/09/21 Javascript
Javascript 按位取反运算符 (~)
2014/02/04 Javascript
ie8模式下click无反应点击option无反应的解决方法
2014/10/11 Javascript
jQuery使用$.get()方法从服务器文件载入数据实例
2015/03/25 Javascript
JavaScript的面向对象编程基础
2015/08/13 Javascript
对于jQuery性能的一些优化建议
2015/08/13 Javascript
基于JavaScript如何实现私有成员的语法特征及私有成员的实现方式
2015/10/28 Javascript
jquery动态增加删减表格行特效
2015/11/20 Javascript
Bootstrap modal使用及点击外部不消失的解决方法
2016/12/13 Javascript
浅谈原型对象的常用开发模式
2017/07/22 Javascript
JavaScript判断浏览器和hack滚动条的写法
2017/07/23 Javascript
nodejs超出最大的调用栈错误问题
2017/12/27 NodeJs
vue中阻止click事件冒泡,防止触发另一个事件的方法
2018/02/08 Javascript
详解mpvue scroll-view自动回弹bug解决方案
2018/10/01 Javascript
解决python3 urllib中urlopen报错的问题
2017/03/25 Python
python爬虫 正则表达式使用技巧及爬取个人博客的实例讲解
2017/10/20 Python
python遍历文件夹,指定遍历深度与忽略目录的方法
2018/07/11 Python
Python tkinter的grid布局及Text动态显示方法
2018/10/11 Python
pytorch获取模型某一层参数名及参数值方式
2019/12/30 Python
Python qrcode 生成一个二维码的实例详解
2020/02/12 Python
python matplotlib模块基本图形绘制方法小结【直线,曲线,直方图,饼图等】
2020/04/26 Python
PythonPC客户端自动化实现原理(pywinauto)
2020/05/28 Python
美国顶级户外凉鞋品牌:Chacos
2017/03/27 全球购物
美国高档百货Nordstrom的折扣店:Nordstrom Rack
2017/11/13 全球购物
医科大学生毕业的自我评价分享
2013/11/12 职场文书
心理健康心得体会
2014/01/02 职场文书
大学活动策划书范文
2014/01/10 职场文书
教师敬业奉献模范事迹材料
2014/05/18 职场文书
派出所正风肃纪剖析材料
2014/10/10 职场文书
数学教师个人工作总结
2015/02/06 职场文书
Java面试题冲刺第十九天--数据库(4)
2021/08/07 Java/Android