python collections模块详解

原文:http://www.cnblogs.com/dahu-daqing/p/7040490.html

1.模块简介

collections包含了一些特殊的容器,针对Python内置的容器,例如list、dict、set和tuple,提供了另一种选择;

namedtuple,可以创建包含名称的tuple;

deque,类似于list的容器,可以快速的在队列头部和尾部添加、删除元素;

Counter,dict的子类,计算可hash的对象;

OrderedDict,dict的子类,可以记住元素的添加顺序;

defaultdict,dict的子类,可以调用提供默认值的函数;

2.模块使用

2.1 Counter

counter可以支持方便、快速的计数,例如,

  1. from collections import *
  2.  
  3. cnt = Counter()
  4. wordList = ["a","b","c","c","a","a"]
  5. for word in wordList:
  6. cnt[word] += 1
  7. print cnt

控制台输出,

  1. Counter({'a': 3, 'c': 2, 'b': 1})

对可迭代的对象进行计数或者从另一个映射(counter)进行初始化,

  1. >>> c = Counter()#一个新的,空的counter
  2. >>> c
  3. Counter()
  4. >>> c = Counter("gallahad")#从可迭代的字符串初始化counter
  5. >>> c
  6. Counter({'a': 3, 'l': 2, 'h': 1, 'g': 1, 'd': 1})
  7. >>> c = Counter({'red':4,'blue':2})#从映射初始化counter
  8. >>> c
  9. Counter({'red': 4, 'blue': 2})
  10. >>> c = Counter(cats = 4,dogs = 8)#从args初始化counter
  11. >>> c
  12. Counter({'dogs': 8, 'cats': 4})

Counter对象类似于字典,如果某个项缺失,会返回0,而不是报出KeyError;

  1. >>> c = Counter(['eggs','ham'])
  2. >>> c['bacon']#没有'bacon'
  3. 0
  4. >>> c['eggs']#有'eggs'
  5. 1

将一个元素的数目设置为0,并不能将它从counter中删除,使用del可以将这个元素删除;

  1. >>> c
  2. Counter({'eggs': 1, 'ham': 1})
  3. >>> c['eggs'] = 0
  4. >>> c
  5. Counter({'ham': 1, 'eggs': 0})#'eggs'依然存在
  6. >>> del c['eggs']
  7. >>> c
  8. Counter({'ham': 1})#'eggs'不存在

Counter对象支持以下三个字典不支持的方法,elements(),most_common(),subtract();

element(),返回一个迭代器,每个元素重复的次数为它的数目,顺序是任意的顺序,如果一个元素的数目少于1,那么elements()就会忽略它;

  1. >>> c = Counter(a=2,b=4,c=0,d=-2,e = 1)
  2. >>> c
  3. Counter({'b': 4, 'a': 2, 'e': 1, 'c': 0, 'd': -2})
  4. >>> list(c.elements())
  5. ['a', 'a', 'b', 'b', 'b', 'b', 'e']

most_common(),返回一个列表,包含counter中n个最大数目的元素
,如果忽略n或者为None,most_common()将会返回counter中的所有元素,元素有着相同数目的将会以任意顺序排列;

  1. >>> Counter('abracadabra').most_common(3)
  2. [('a', 5), ('r', 2), ('b', 2)]
  3. >>> Counter('abracadabra').most_common()
  4. [('a', 5), ('r', 2), ('b', 2), ('c', 1), ('d', 1)]
  5. >>> Counter('abracadabra').most_common(None)
  6. [('a', 5), ('r', 2), ('b', 2), ('c', 1), ('d', 1)]

subtract(),从一个可迭代对象中或者另一个映射(或counter)中,元素相减,类似于dict.update(),但是subtracts 数目而不是替换它们,输入和输出都有可能为0或者为负;

  1. >>> c = Counter(a=4,b=2,c=0,d=-2)
  2. >>> d = Counter(a=1,b=2,c=-3,d=4)
  3. >>> c.subtract(d)
  4. >>> c
  5. Counter({'a': 3, 'c': 3, 'b': 0, 'd': -6})

update(),从一个可迭代对象中或者另一个映射(或counter)中所有元素相加,类似于dict.upodate,是数目相加而非替换它们,另外,可迭代对象是一个元素序列,而非(key,value)对构成的序列;

  1. >>> c
  2. Counter({'a': 4, 'b': 2, 'c': 0, 'd': -2})
  3. >>> d
  4. Counter({'d': 4, 'b': 2, 'a': 1, 'c': -3})
  5. >>> c.update(d)
  6. >>> c
  7. Counter({'a': 5, 'b': 4, 'd': 2, 'c': -3})

Counter对象常见的操作,

  1. >>> c
  2. Counter({'a': 5, 'b': 4, 'd': 2, 'c': -3})
  3. >>> sum(c.values())# 统计所有的数目
  4. 8
  5. >>> list(c)# 列出所有唯一的元素
  6. ['a', 'c', 'b', 'd']
  7. >>> set(c)# 转换为set
  8. set(['a', 'c', 'b', 'd'])
  9. >>> dict(c)# 转换为常规的dict
  10. {'a': 5, 'c': -3, 'b': 4, 'd': 2}
  11. >>> c.items()# 转换为(elem,cnt)对构成的列表
  12. [('a', 5), ('c', -3), ('b', 4), ('d', 2)]
  13. >>> c.most_common()[:-4:-1]# 输出n个数目最小元素
  14. [('c', -3), ('d', 2), ('b', 4)]
  15. >>> c += Counter()# 删除数目为0和为负的元素
  16. >>> c
  17. Counter({'a': 5, 'b': 4, 'd': 2})
  18. >>> Counter(dict(c.items()))# 从(elem,cnt)对构成的列表转换为counter
  19. Counter({'a': 5, 'b': 4, 'd': 2})
  20. >>> c.clear()# 清空counter
  21. >>> c
  22. Counter()

在Counter对象进行数学操作,得多集合(counter中元素数目大于0)加法和减法操作,是相加或者相减对应元素的数目;交集和并集返回对应数目的最小值和最大值;每个操作均接受暑促是有符号的数目,但是输出并不包含数目为0或者为负的元素;

  1. >>> c = Counter(a=3,b=1,c=-2)
  2. >>> d = Counter(a=1,b=2,c=4)
  3. >>> c+d#求和
  4. Counter({'a': 4, 'b': 3, 'c': 2})
  5. >>> c-d#求差
  6. Counter({'a': 2})
  7. >>> c & d#求交集
  8. Counter({'a': 1, 'b': 1})
  9. >>> c | d#求并集
  10. Counter({'c': 4, 'a': 3, 'b': 2})

2.2 deque

deque是栈和队列的一种广义实现,deque是"double-end queue"的简称;deque支持线程安全、有效内存地以近似O(1)的性能在deque的两端插入和删除元素,尽管list也支持相似的操作,但是它主要在固定长度操作上的优化,从而在pop(0)和insert(0,v)(会改变数据的位置和大小)上有O(n)的时间复杂度。

deque支持如下方法,

append(x), 将x添加到deque的右侧;

appendleft(x), 将x添加到deque的左侧;

clear(), 将deque中的元素全部删除,最后长度为0;

count(x), 返回deque中元素等于x的个数;

extend(iterable), 将可迭代变量iterable中的元素添加至deque的右侧;

extendleft(iterable), 将变量iterable中的元素添加至deque的左侧,往左侧添加序列的顺序与可迭代变量iterable中的元素相反;

pop(), 移除和返回deque中最右侧的元素,如果没有元素,将会报出IndexError;

popleft(), 移除和返回deque中最左侧的元素,如果没有元素,将会报出IndexError;

remove(value), 移除第一次出现的value,如果没有找到,报出ValueError;

reverse(), 反转deque中的元素,并返回None;

rotate(n), 从右侧反转n步,如果n为负数,则从左侧反转,d.rotate(1)等于d.appendleft(d.pop());

maxlen, 只读的属性,deque的最大长度,如果无解,就返回None;

除了以上的方法之外,deque还支持迭代、序列化、len(d)、reversed(d)、copy.copy(d)、copy.deepcopy(d),通过in操作符进行成员测试和下标索引,索引的时间复杂度是在两端是O(1),在中间是O(n),为了快速获取,可以使用list代替。

  1. >>> from collections import deque
  2. >>> d = deque('ghi')# 新建一个deque,有三个元素
  3. >>> for ele in d:# 遍历deque
  4. ... print ele.upper()
  5. ...
  6. ...
  7. G
  8. H
  9. I
  10. >>> d.append('j')# deque右侧添加一个元素
  11. >>> d.appendleft('f')# deque左侧添加一个元素
  12. >>> d# 打印deque
  13. deque(['f', 'g', 'h', 'i', 'j'])
  14. >>> d.pop()# 返回和移除最右侧元素
  15. 'j'
  16. >>> d.popleft()# 返回和移除最左侧元素
  17. 'f'
  18. >>> list(d)# 以列表形式展示出deque的内容
  19. ['g', 'h', 'i']
  20. >>> d[0]# 获取最左侧的元素
  21. 'g'
  22. >>> d[-1]# 获取最右侧的元素
  23. 'i'
  24. >>> list(reversed(d))# 以列表形式展示出倒序的deque的内容
  25. ['i', 'h', 'g']
  26. >>> 'h' in d# 在deque中搜索
  27. True
  28. >>> d.extend('jkl')# 一次添加多个元素
  29. >>> d
  30. deque(['g', 'h', 'i', 'j', 'k', 'l'])
  31. >>> d.rotate(1)# 往右侧翻转
  32. >>> d
  33. deque(['l', 'g', 'h', 'i', 'j', 'k'])
  34. >>> d.rotate(-1)# 往左侧翻转
  35. >>> d
  36. deque(['g', 'h', 'i', 'j', 'k', 'l'])
  37. >>> deque(reversed(d))# 以逆序新建一个deque
  38. deque(['l', 'k', 'j', 'i', 'h', 'g'])
  39. >>> d.clear()# 清空deque
  40. >>> d.pop()# 不能在空的dequepop
  41. Traceback (most recent call last):
  42. File "<input>", line 1, in <module>
  43. IndexError: pop from an empty deque
  44. >>> d.extendleft('abc')# 以输入的逆序向左扩展
  45. >>> d
  46. deque(['c', 'b', 'a'])

其他的应用:

1.限定长度的deque提供了Unix中tail命令相似的功能;

  1. from collections import deque
  2.  
  3. def tail(filename,n = 10):
  4. "Return the last n lines of a file"
  5. return deque(open(filename),n)
  6.  
  7. print tail("temp.txt",10)

2.使用deque维护一个序列(右侧添加元素,左侧删除元素)中窗口的平均值;

  1. from collections import deque
  2. import itertools
  3.  
  4. def moving_average(iterable,n = 3):
  5. it = iter(iterable)
  6. d = deque(itertools.islice(it,n-1))
  7. # 第一次只有两个元素,再右移的过程中,需要先删除最左端的元素,因此现在最左端加入0
  8. d.appendleft(0)
  9. s = sum(d)
  10. for ele in it:
  11. # 删除最左端的元素,再加上新元素
  12. s += ele - d.popleft()
  13. # 右端添加新元素
  14. d.append(ele)
  15. yield s / float(n)
  16.  
  17. array = [40,30,50,46,39,44]
  18. for ele in moving_average(array,n=3):
  19. print ele

3.rotate()方法提供了一种实现deque切片和删除的方式,例如,del d[n]依赖于rotate方法的纯Python实现,如下,

  1. from collections import deque
  2.  
  3. def delete_nth(d,n):
  4. # 将前n个元素翻转到右侧
  5. d.rotate(-n)
  6. # 删除第n个元素
  7. d.popleft()
  8. # 再将后n个元素翻转到左侧
  9. d.rotate(n)
  10.  
  11. d = deque("abcdefg")
  12. delete_nth(d,n = 3)
  13. print d

4.slice依赖于rotate方法的纯Python实现,如下,

  1. from collections import deque
  2.  
  3. def slice(d,m,n):
  4. # 先将前面m个元素翻转到右侧
  5. d.rotate(-m)
  6. i = m
  7. sliceList = []
  8. # 依次将[m,n]区间内的元素出栈
  9. while i < n:
  10. item = d.popleft()
  11. sliceList.append(item)
  12. i+=1
  13. # 再将出栈的元素扩展到deque右侧
  14. d.extend(sliceList)
  15. # 再将后面n个元素翻转到左侧
  16. d.rotate(n)
  17. return sliceList
  18.  
  19. d = deque("abcdefg")
  20. print slice(d,1,5)

2.3 defaultdict

defaultdict是内置数据类型dict的一个子类,基本功能与dict一样,只是重写了一个方法__missing__(key)和增加了一个可写的对象变量default_factory。

  1. >>> dir(defaultdict)
  2. ['__class__', '__cmp__', '__contains__', '__copy__', '__delattr__', '__delitem__
  3. ', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__
  4. ', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__',
  5. '__missing__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '
  6. __setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'clear
  7. ', 'copy', 'default_factory', 'fromkeys', 'get', 'has_key', 'items', 'iteritems'
  8. , 'iterkeys', 'itervalues', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'v
  9. alues', 'viewitems', 'viewkeys', 'viewvalues']
  10. >>> dir(dict)
  11. ['__class__', '__cmp__', '__contains__', '__delattr__', '__delitem__', '__doc__'
  12. , '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__',
  13. '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '_
  14. _new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__'
  15. , '__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy', 'fromkeys', 'get
  16. ', 'has_key', 'items', 'iteritems', 'iterkeys', 'itervalues', 'keys', 'pop', 'po
  17. pitem', 'setdefault', 'update', 'values', 'viewitems', 'viewkeys', 'viewvalues']

missing(key)

  1. 如果default_factory属性为None,就报出以key作为遍历的KeyError异常;
  2. 如果default_factory不为None,就会向给定的key提供一个默认值,这个值插入到词典中,并返回;
  3. 如果调用default_factory报出异常,这个异常在传播时不会改变;
  4. 这个方法是当要求的key不存在时,dict类中的__getitem()__方法所调用,无论它返回或者报出什么,最终返回或报出给__getitem()__;
  5. 只有__getitem__()才能调用__missing__(),这意味着,如果get()起作用,如普通的词典,将会返回None作为默认值,而不是使用default_factory;

default_factory, 这个属性用于__missing__()方法,使用构造器中的第一个参数初始化;

使用list作为default_factory,很容易将一个key-value的序列转换为一个关于list的词典;

  1. >>> from collections import *
  2. >>> s = [('yellow',1),('blue',2),('yellow',3),('blue',4),('red',5)]
  3. >>> d = defaultdict(list)
  4. >>> for k,v in s: d[k].append(v)
  5. ...
  6. >>> d.items()
  7. [('blue', [2, 4]), ('red', [5]), ('yellow', [1, 3])]

当每一个key第一次遇到时,还没有准备映射,首先会使用default_factory函数自动创建一个空的list,list.append()操作将value添加至新的list中,当key再次遇到时,通过查表,返回对应这个key的list,list.append()会将新的value添加至list,这个技术要比dict.setdefault()要简单和快速。

  1. >>> e = {}
  2. >>> for k,v in s: e.setdefault(k,[]).append(v)
  3. ...
  4. >>> e.items()
  5. [('blue', [2, 4]), ('red', [5]), ('yellow', [1, 3])]

设置default_factory为int,使得defaultdict可以用于计数,

  1. >>> s = "mississippi"
  2. >>> d = defaultdict(int)
  3. >>> for k in s: d[k]+=1
  4. ...
  5. >>> d.items()
  6. [('i', 4), ('p', 2), ('s', 4), ('m', 1)]

当一个字母第一次遇到,默认从default_factory中调用int()用于提供一个默认为0的计数,递增操作会增加每个字母的计数。

函数int()经常返回0,是常量函数的一种特例。一种更快和更灵活的创建常量函数的方式是使用itertools.repeat(),可以提供任意常量值(不仅仅是0),

  1. >>> import itertools
  2. >>> def constant_factory(value):
  3. ... return itertools.repeat(value).next
  4. ...
  5. >>> d = defaultdict(constant_factory('<missing>'))
  6. >>> d.update(name = "John",action = "ran")
  7. >>> "%(name)s %(action)s to %(object)s"%d
  8. 'John ran to <missing>'

将default_factory设置为set,使得defaultdict可以建立一个关于set的词典,

  1. >>> s = [('red', 1), ('blue', 2), ('red', 3), ('blue', 4), ('red', 1), ('blue',
  2. 4)]
  3. >>> d = defaultdict(set)
  4. >>> for k,v in s:d[k].add(v)
  5. ...
  6. >>> d.items()
  7. [('blue', set([2, 4])), ('red', set([1, 3]))]

2.4 namedtuple

命名的元组,意味给元组中的每个位置赋予含义,意味着代码可读性更强,namedtuple可以在任何常规元素使用的地方使用,而且它可以通过名称来获取字段信息而不仅仅是通过位置索引。

  1. >>> from collections import *
  2. >>> Point = namedtuple('Point',['x','y'],verbose = True)
  3. class Point(tuple):
  4. 'Point(x, y)'
  5.  
  6. __slots__ = ()
  7.  
  8. _fields = ('x', 'y')
  9.  
  10. def __new__(_cls, x, y):
  11. 'Create new instance of Point(x, y)'
  12. return _tuple.__new__(_cls, (x, y))
  13.  
  14. @classmethod
  15. def _make(cls, iterable, new=tuple.__new__, len=len):
  16. 'Make a new Point object from a sequence or iterable'
  17. result = new(cls, iterable)
  18. if len(result) != 2:
  19. raise TypeError('Expected 2 arguments, got %d' % len(result))
  20. return result
  21.  
  22. def __repr__(self):
  23. 'Return a nicely formatted representation string'
  24. return 'Point(x=%r, y=%r)' % self
  25.  
  26. def _asdict(self):
  27. 'Return a new OrderedDict which maps field names to their values'
  28. return OrderedDict(zip(self._fields, self))
  29.  
  30. def _replace(_self, **kwds):
  31. 'Return a new Point object replacing specified fields with new values'
  32. result = _self._make(map(kwds.pop, ('x', 'y'), _self))
  33. if kwds:
  34. raise ValueError('Got unexpected field names: %r' % kwds.keys())
  35. return result
  36.  
  37. def __getnewargs__(self):
  38. 'Return self as a plain tuple. Used by copy and pickle.'
  39. return tuple(self)
  40.  
  41. __dict__ = _property(_asdict)
  42.  
  43. def __getstate__(self):
  44. 'Exclude the OrderedDict from pickling'
  45. pass
  46.  
  47. x = _property(_itemgetter(0), doc='Alias for field number 0')
  48.  
  49. y = _property(_itemgetter(1), doc='Alias for field number 1')
  1. >>> p = Point(11,y = 22)# 实例化一个对象,可以使用位置或者关键字
  2. >>> p[0] + p[1]# 通过索引访问元组中的元素
  3. 33
  4. >>> x,y = p# 分开,类似于常规的元组
  5. >>> x,y
  6. (11, 22)
  7. >>> p.x + p.y# 通过名称访问元素
  8. 33
  9. >>> p# 可读的__repr__,通过name = value风格
  10. Point(x=11, y=22)
  1. namedtuple在给csv或者sqlite3返回的元组附上名称特别有用,
  1. from collections import *
  2. import csv
  3.  
  4. EmployeeRecord = namedtuple('EmployeeRecord','name, age, title, department, paygrade')
  5. for emp in map(EmployeeRecord._make,csv.reader(open("employee.csv","rb"))):
  6. print emp.name,emp.title
  7.  
  8. # import sqlite3
  9. # conn = sqlite3.connect('/companydata')
  10. # cursor = conn.cursor()
  11. # cursor.execute('SELECT name, age, title, department, paygrade FROM employees')
  12. # for emp in map(EmployeeRecord._make, cursor.fetchall()):
  13. # print emp.name, emp.title

控制台输出,

  1. Jim RD
  2. Tom Manager

除了从tuples继承的方法之外,namedtuple还支持三种方法和一个属性,为了避免和名称冲突,这些方法和属性以下划线开始。

**somenamedtuple._make(),** 从已有的序列或者可迭代的对象中创建一个新的对象;

  1. >>> Point = namedtuple('Point', ['x', 'y'])
  2. >>> t = [33,44]
  3. >>> Point._make(t)
  4. Point(x=33, y=44)

**somenamedtuple._asdict(),** 返回一个OrderDict,由名称到对应值建立的映射;

  1. >>> p = Point(x = 11,y = 22)
  2. >>> p
  3. Point(x=11, y=22)
  4. >>> pDict = p._asdict()
  5. >>> pDict
  6. OrderedDict([('x', 11), ('y', 22)])

**somenamedtuple._replace(),** 返回一个新的namedtuple对象,用新值替换指定名称中的值;

  1. >>> p2 = p._replace(x = 33)
  2. >>> p2
  3. Point(x=33, y=22)

**somenamedtuple._fields,** 以字符串构成的元组的形式返回namedtuple中的名称,在自省或者基于一个已经存在的namedtuple中创建新的namedtuple时,非常有用;

  1. >>> p._fields
  2. ('x', 'y')
  3. >>> Color = namedtuple('Color',"red green blu")
  4. >>> Pixel = namedtuple('Pixel',Point._fields + Color._fields)
  5. >>> Pixel(11,22,128,255,0)
  6. Pixel(x=11, y=22, red=128, green=255, blu=0)

当名称存储在字符串中,可以使用getattr()函数进行检索,

  1. >>> getattr(p,'x')
  2. 11

使用**操作符,可以将一个字典转换成namedtuple,

  1. >>> d = {'x':11,'y':22}
  2. >>> Point(**d)
  3. Point(x=11, y=22)

由于namedtuple也是Python中的一个类,因此再子类中,它很容易添加或者修改一些功能,如下是添加一个可计算名称和固定长度的输出格式;子类中的__slots__是一个空的元组,可以通过避免词典实例的创建来节约内存开销;

  1. class Point(namedtuple('Point','x y')):
  2. __slots__ = ()
  3. @property
  4. def hypot(self):
  5. return (self.x ** 2 + self.y**2) ** 0.5
  6. def __str__(self):
  7. return "Point:x = %6.3f y = %6.3f hypot = %6.3f" %(self.x,self.y,self.hypot)
  8.  
  9. for p in Point(3,4),Point(14,5/7.):
  10. print p

控制台输出,

  1. Point:x = 3.000 y = 4.000 hypot = 5.000
  2. Point:x = 14.000 y = 0.714 hypot = 14.018

子类在增加、存储名称时,并不是非常有用,相反,可以容易地通过_fields属性来创建一个新的namedtuple;

  1. >>> Point3D = namedtuple("Point3D",Point._fields + ('z',))
  2. >>> Point3D._fields
  3. ('x', 'y', 'z')

默认值可以通过_replace()来实现,以便于标准化一个原型实例;

  1. >>> Account = namedtuple('Account','owner balance transaction_count')
  2. >>> default_account = Account('<owner name>',0.0,0)
  3. >>> johns_account = default_account._replace(owner = "John")
  4. >>> johns_account
  5. Account(owner='John', balance=0.0, transaction_count=0)

枚举类型常量可以通过namedtuple来实现,更简单和有效的方式是通过意见简单的类声明;

  1. Status = namedtuple('Status','open pending closed')._make(range(3))
  2. print Status
  3.  
  4. class Status:
  5. open, pending, closed = range(3)
  6.  
  7. print Status.open
  8. print Status.pending
  9. print Status.closed

控制台输出,

  1. Status(open=0, pending=1, closed=2)
  2. 0
  3. 1
  4. 2

2.5 OrderedDict

OrderedDict类似于正常的词典,只是它记住了元素插入的顺序,当在有序的词典上迭代时,返回的元素就是它们第一次添加的顺序。

class collections.OrderedDict,返回已给dict的子类,支持常规的dict的方法,OrderedDict是一个记住元素首次插入顺序的词典,如果一个元素重写已经存在的元素,那么原始的插入位置保持不变,如果删除一个元素再重新插入,那么它就在末尾。

OrderedDict.popitem(last=True),popitem方法返回和删除一个(key,value)对,如果last=True,就以LIFO方式执行,否则以FIFO方式执行。

OrderedDict也支持反向迭代,例如reversed()。

OrderedDict对象之间的相等测试,例如,list(od1.items()) == list(od2.items()),是对顺序敏感的;OrderedDict和其他的映射对象(例如常规的词典)之间的相等测试是顺序不敏感的,这就允许OrderedDict对象可以在使用常规词典的地方替换掉常规词典。

OrderedDict构造器和update()方法可以接受关键字变量,但是它们丢失了顺序,因为Python的函数调用机制是将一个无序的词典传入关键字变量。

一个有序的词典记住它的成员插入的顺序,可以使用排序函数,将其变为排序的词典,

  1. >>> d = {"banana":3,"apple":2,"pear":1,"orange":4}
  2. >>> # dict sorted by key
  3. >>> OrderedDict(sorted(d.items(),key = lambda t:t[0]))
  4. OrderedDict([('apple', 2), ('banana', 3), ('orange', 4), ('pear', 1)])
  5. >>> # dict sorted by value
  6. >>> OrderedDict(sorted(d.items(),key = lambda t:t[1]))
  7. OrderedDict([('pear', 1), ('apple', 2), ('banana', 3), ('orange', 4)])
  8. >>> # dict sorted by length of key string
  9. >>>a = OrderedDict(sorted(d.items(),key = lambda t:len(t[0])))
  10. >>>a
  11. OrderedDict([('pear', 1), ('apple', 2), ('orange', 4), ('banana', 3)])
  12. >>> del a['apple']
  13. >>> a
  14. OrderedDict([('pear', 1), ('orange', 4), ('banana', 3)])
  15. >>> a["apple"] = 2
  16. >>> a
  17. OrderedDict([('pear', 1), ('orange', 4), ('banana', 3), ('apple', 2)])

当元素删除时,排好序的词典保持着排序的顺序;但是当新元素添加时,就会被添加到末尾,就不能保持已排序。

创建一个有序的词典,可以记住最后插入的key的顺序,如果一个新的元素要重写已经存在的元素,那么原始的插入位置就会改变成末尾,

  1. >>> class LastUpdatedOrderedDict(OrderedDict):
  2. ... def __setitem__(self,key,value):
  3. ... if key in self:
  4. ... del self[key]
  5. ... OrderedDict.__setitem__(self, key, value)
  6. ...
  7. >>> obj = LastUpdatedOrderedDict()
  8. >>> obj["apple"] = 2
  9. >>> obj["windows"] = 3
  10. >>> obj
  11. LastUpdatedOrderedDict([('apple', 2), ('windows', 3)])
  12. >>> obj["apple"] = 1
  13. >>> obj
  14. LastUpdatedOrderedDict([('windows', 3), ('apple', 1)])

一个有序的词典可以和Counter类一起使用,counter对象就可以记住元素首次出现的顺序;

  1. class OrderedCounter(Counter,OrderedDict):
  2. def __repr__(self):
  3. return "%s(%r)"%(self.__class__.__name__,OrderedDict(self))
  4.  
  5. def __reduce__(self):
  6. return self.__class__,(OrderedDict(self))
  7.  
  8. #和OrderDict一起使用的Counter对象
  9. obj = OrderedCounter()
  10. wordList = ["b","a","c","a","c","a"]
  11. for word in wordList:
  12. obj[word] += 1
  13. print obj
  14.  
  15. # 普通的Counter对象
  16. cnt = Counter()
  17. wordList = ["b","a","c","a","c","a"]
  18. for word in wordList:
  19. cnt[word] += 1
  20. print cnt

控制台输出,

  1. OrderedCounter(OrderedDict([('b', 1), ('a', 3), ('c', 2)]))
  2. Counter({'a': 3, 'c': 2, 'b': 1})

3.Reference

8.3. collections — High-performance container datatypes

(转)python collections模块详解的更多相关文章

  1. python collections模块详解

    参考老顽童博客,他写的很详细,例子也很容易操作和理解. 1.模块简介 collections包含了一些特殊的容器,针对Python内置的容器,例如list.dict.set和tuple,提供了另一种选 ...

  2. python time模块详解

    python time模块详解 转自:http://blog.csdn.net/kiki113/article/details/4033017 python 的内嵌time模板翻译及说明  一.简介 ...

  3. python docopt模块详解

    python docopt模块详解 docopt 本质上是在 Python 中引入了一种针对命令行参数的形式语言,在代码的最开头使用 """ ""&q ...

  4. python pathlib模块详解

    python pathlib模块详解    

  5. Python Fabric模块详解

    Python Fabric模块详解 什么是Fabric? 简单介绍一下: ​ Fabric是一个Python的库和命令行工具,用来提高基于SSH的应用部署和系统管理效率. 再具体点介绍一下,Fabri ...

  6. python time 模块详解

    Python中time模块详解 发表于2011年5月5日 12:58 a.m.    位于分类我爱Python 在平常的代码中,我们常常需要与时间打交道.在Python中,与时间处理有关的模块就包括: ...

  7. python常用模块详解

    python常用模块详解 什么是模块? 常见的场景:一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀. 但其实import加载的模块分为四个通用类别: 1 使用p ...

  8. python os模块详解

    一.Python os模块(Linux环境) 1.1 执行shell命令 os.system('cmd') 执行命令不保存结果 os.popen('command') 执行后返回结果,使用.read( ...

  9. Python ZipFile模块详解(转)

    Python zipfile模块用来做zip格式编码的压缩和解压缩的,zipfile里有两个非常重要的class, 分别是ZipFile和ZipInfo, 在绝大多数的情况下,我们只需要使用这两个cl ...

随机推荐

  1. [转][译] 存储引擎原理:LSM

    原译文地址:http://www.tuicool.com/articles/qqQV7za http://www.zhihu.com/question/19887265 http://blog.csd ...

  2. WorkFlow 工作流 学习笔记

    传统ERP为制造业企业产供销人财物的管理提供了一整套优化企业资源利用,集物流.信息流.资金流为一体的现代化管理工具.但是它在过程集成和企业间集成方面存在不足.具体表现在: 1.传统ERP是一个面向功能 ...

  3. Oracle 表关联性 Update 语句的改写,推荐改写方法1

    同事写了一个逻辑稍复杂的Update 语句,觉得在代码可读性上有些转圈,交给我帮忙改下. 以下根据原SQL,使用两种方法进行改写,个人推荐方法1的改写.方法2拆分两个SQL来写,代码可读性最强,但是S ...

  4. Reporting Service服务SharePoint集成模式安装配置(6、安装Reporting services Add-in for SharePoint 外接程序)

    第五步骤 : 安装Reporting services Add-in for SharePoint 外接程序 RS 外接程序是在 SharePoint 服务器上运行用于 SharePoint 产品的 ...

  5. Verilog MIPS32 CPU(五)-- CP0

    Verilog MIPS32 CPU(一)-- PC寄存器 Verilog MIPS32 CPU(二)-- Regfiles Verilog MIPS32 CPU(三)-- ALU Verilog M ...

  6. input获取、失去焦点对输入内容做验证

    获取焦点 # 重新获取焦掉后,会将指定标签中的css样式删除,这里为标记错误的css样式(将文本框标红) $("form input").focus(function () { $ ...

  7. 卸载jdk1.7

    卸载jdk1.7: 1.开始->程序->控制面板 ->卸载程序->程序和功能 2.找到jdk的两个程序:java 7 update 45和java(TM)SE Developm ...

  8. js中闭包和对象相关知识点

    学习js时候,读到几篇不错的博客.http://www.cnblogs.com/yexiaochai/p/3802681.html一,作用域 和C.C++.Java 等常见语言不同,JavaScrip ...

  9. python3之循环

    本节主要介绍python中循环语句的用法以及其他一些语句exec等,文章后面附有之前的文章: 循环语句 if是值执行一次而循环时在条件满足情况下可以执行相同语句多次:使用循环可以轻松实现序列,词典等的 ...

  10. Windows下Jmeter安装出现Not able to find Java executable or version问题解决方案

    安装好java1.8.jmeter4.0,并java -version正常,jmeter也能正常使用.某一次使用突然出现Not able to find Java executable or vers ...