python中的collections模块学习

  • Python在一些内置的数据类型,比如str, int, list, tuple, dict等,之后又提供了比较高级的额外的数据类型, 共有以下几种:Counter, deque, defaultdict, namedtuple, OrderedDict

那么接下来一个个的攻克它们。

一.namedtuple

namedtuple的函数原型如下:

1
2
def namedtuple(typename, field_names, verbose=False, rename=False):
"""Returns a new subclass of tuple with named fields.
  • 作用就是通过将可迭代对象设置字段名,可使用名称来访问元素的数据对象。
    比较重要参数释义:
    • typename: 自定义名,字符串类型
    • field_names: 字段名,list类型

如下例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
`>>> Point = namedtuple('Point', ['x', 'y'])
>>> Point.__doc__ # 新类的文档字符串
'Point(x, y)'

>>> p = Point(11, y=22) # 通过位置参数或关键字参数实例化
>>> p[0] + p[1] # 像普通元组一样使用索引
33

>>> x, y = p # 像普通元组一样解包
(11, 22)

>>> p.x + p.y # 通过字段名访问
33

>>> d = p._asdict() # 转换为字典
>>> d['x']
11

>>> Point(**d) # 从字典转换过来
Point(x=11, y=22)

>>> p._replace(x=100) # _replace() is like str.replace() but targets named fields
Point(x=100, y=22)

再举一个:chestnut:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from collections import namedtuple

tuples = [
('Bman', 22, 'Python'),
('Jack', 24, 'C'),
]

p = namedtuple("Code", ['name', 'age', 'language'])
print p # <class '__main__.Code'>
print p._fields # ('name', 'age', 'language')
print p.__doc__ # Code(name, age, language)

for i in tuples:
_i = p._make(i)
print i, _i, _i.name, _i.age, _i.language
# ('Bman', 22, 'Python') Code(name='Bman', age=22, language='Python') Bman 22 Python
# ('Jack', 24, 'C') Code(name='Jack', age=24, language='C') Jack 24 C

二.deque

deque其实是 double-ended queue 的缩写,翻译过来就是双端队列,它最大的好处就是实现了从队列 头部快速增加和取出对象: popleft(),appendleft()

  • 该类的原型如下:

    1
    deque([iterable[, maxlen]]) --> deque object
  • 该类有以下方法:
    append: 添加元素到右侧的双端队列
    appendleft: 添加元素到左侧的双端队列
    clear: 移除所有元素
    count: D.count(value) -> integer, 返回出现的值数
    extend: 通过可迭代元素扩展右侧的双端队列
    extendleft: 与上相反
    pop: 删除并返回最右边的元素

  • 虽然原生的list也可以从头部添加和取出对象等方法:

    1
    2
    lis.insert(0, v)
    lis.pop(0)
  • 但是与list不同的是list对象的这两种用法的时间复杂度是 O(n) ,也就是说随着元素数量的增加耗时呈线性上升。而使用deque对象则是 O(1) 的复杂度,所以当你的代码有这样的需求的时候, 一定要记得使用deque。

  • 我们可以创建一个空的deque对象:

    1
    2
    d = deque()
    # deque([])

然后进行操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
d.append(1)
d.append('2')
print d, len(d) # deque([1, '2']) 2
print d[0] # 1

d.appendleft('a')
print d # deque(['a', 1, '2'])

print d.count('a') # 1

d.extend(['a', 'b', 'c'])
print d # deque(['a', 1, '2', 'a', 'b', 'c'])

d.extendleft(['m', 'n'])
print d # deque(['n', 'm', 'a', 1, '2', 'a', 'b', 'c'])

print d.pop() # c
print d.popleft() # n

print d # deque(['m', 'a', 1, '2', 'a', 'b'])
d.remove('a')
print d # deque(['m', 1, '2', 'a', 'b'])

d = deque('abcde')
print d
for i in range(len(d)):
d.rotate()
print i, d
# 输出:
deque(['a', 'b', 'c', 'd', 'e'])
0 deque(['e', 'a', 'b', 'c', 'd'])
1 deque(['d', 'e', 'a', 'b', 'c'])
2 deque(['c', 'd', 'e', 'a', 'b'])
3 deque(['b', 'c', 'd', 'e', 'a'])
4 deque(['a', 'b', 'c', 'd', 'e'])

下面例子实现一个跑马灯效果:

1
2
3
4
5
6
7
8
9
10
11
import sys
import time
from collections import deque

loading = deque('>--------------------')

while True:
print '\r%s' % ''.join(loading), # 注意:"\r"表示回车(将光标移至本行开头)这里不能省略后面的逗号
loading.rotate() # 默认1
sys.stdout.flush()
time.sleep(0.08)

三.Counter

实现计数功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
`>>> c = Counter('abcdeabcdabcaba')  # count elements from a string

>>> c.most_common(3) # 出现最多的三个元素
[('a', 5), ('b', 4), ('c', 3)]

>>> sorted(c) # 列出所有唯一元素
['a', 'b', 'c', 'd', 'e']

>>> c.elements() # 迭代器
<itertools.chain at 0x1094c0e50>
>>> sorted(c.elements()) # 列出所有元素
['a', 'a', 'a', 'a', 'a', 'b', 'b', 'b', 'b', 'c', 'c', 'c', 'd', 'd', 'e']

>>> ''.join(sorted(c.elements()))
'aaaaabbbbcccdde'

>>> sum(c.values()) # total of all counts
15

>>> c['a'] # 元素a出现次数
5

>>> for elem in 'shazam': # 通过可迭代对象更新counts
... c[elem] += 1 # by adding 1 to each element's count
>>> c['a'] # now there are seven 'a'
7

>>> del c['b'] # remove all 'b'
>>> c['b'] # now there are zero 'b'
0

>>> d = Counter('simsalabim') # make another counter
>>> c.update(d) # add in the second counter
>>> c['a'] # now there are nine 'a'
9

>>> c.clear() # empty the counter
>>> c
Counter()

Note: If a count is set to zero or reduced to zero, it will remain
in the counter until the entry is deleted or the counter is cleared:

>>> c = Counter('aaabbc')
>>> c['b'] -= 2 # reduce the count of 'b' by two
>>> c.most_common() # 'b' is still in, but its count is zero
[('a', 3), ('c', 1), ('b', 0)]

四.OrderedDict

OrderedDict相对于dict来说也就是有序字典。用法与dict类似,它有如下常用方法:

  • clear
    1
    od.clear() -> None.  Remove all items from od

如下例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
from collections import OrderedDict

items = (
('A', 1),
('B', 2),
('C', 3)
)

regular_dict = dict(items)
ordered_dict = OrderedDict(items)

# 无序
for k, v in regular_dict.items():
print k, v

# 有序
for k, v in ordered_dict.items():
print k, v


# Result:
Regular Dict:
A 1
C 3
B 2
Ordered Dict:
A 1
B 2
C 3

五.defaultdict

Python原生的数据结构dict的时候,如果用 `d[key]
这样的方式访问, 当指定的key不存在时,是会抛出KeyError异常的。如果使用defaultdict,只要你传入一个默认的工厂方法,那么请求一个不存在的key时, 便会调用这个工厂方法使用其结果来作为这个key的默认值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
members = [
# Age, name
['male', 'John'],
['male', 'Jack'],
['female', 'Lily'],
['male', 'Pony'],
['female', 'Lucy'],
]

result = defaultdict(list)
print result # defaultdict(<type 'list'>, {})

for sex, name in members:
result[sex].append(name) # 将sex做key,value为list类型,append(name)

print result # defaultdict(<type 'list'>, {'male': ['John', 'Jack', 'Pony'], 'female': ['Lily', 'Lucy']})

defaultdict(list)的用法和dict.setdefault(key, [])比较类似,上述代码使用setdefault实现如下:

1
2
3
4
5
result = {}
for sex, name in members:
result.setdefault(sex, []).append(name)

print result