在内置数据类型(dict、list、set、tuple)的基础上,collections模块还提供了几个额外的数据类型:Counter、deque、defaultdict、namedtuple和OrderedDict等。
namedtuple: 生成可以使用名字来访问元素内容的tuple
deque: 双端队列,可以快速的从另外一侧追加和推出对象
Counter: 计数器,主要用来计数
OrderedDict: 有序字典
defaultdict: 带有默认值的字典
tuple
表示不变集合,例如:一个点的二维坐标
p = (1, 2)
但是,看到(1,2)很难看出这个tuple是用来表示一个坐标的。
这时,namedtuple
就派上了用场:
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])
p = Point(1, 2)
print(p.x, p.y)
# 1, 2
namedtuple
的定义:
# namedtuple('名称', [属性list])
Circle = namedtuple('Circle', ['x', 'y', 'r'])
在流畅的python(Fluent Python)
中,其作者Luciano Ramalho
用namedtuple
徒手实现了一副扑克牌
from collections import namedtuple
Cards = namedtuple('Card', ['rank', 'suit'])
class FrenchDeck:
ranks = [n for n in range(2, 11)] + list('JQKA')
suit = 'spades diamonds clubs hearts'.split()
def __init__(self):
self._card = [Cards(rank, suit) for rank in ranks for suit in suits]
def __len__(self):
return len(self._card)
def __getitem__(self, position):
return self._card[position]
使用list存储数据时,按索引访问元素很快,但是插入和删除元素就很慢了,因为list是线性存储,数据量大的时候,插入和删除效率很低。
deque
是为了高效实现插入和删除操作的双向列表,适合用于队列和栈:
from collections import deque
q = deque(['a', 'b', 'c'])
q.append('x')
q.appendleft('y')
print(q)
# deque(['y', 'a', 'b', 'c', 'x'])
deque
除了实现list的append()
和pop()
操作外,还支持appendleft()
和popleft()
,这样就可以非常高效地往头部添加或删除元素。
使用dict时,Key是无序的。(在python 3.7+版本中dict默认保持插入顺序)。在对dict做迭代时,我们无法确定key的顺序。
如果需要保持key的顺序,可以用OrderedDict:
from collections import OrderedDict
d = dict([('a',1), ('b',2), ('c',3)])
print(d)
# {'a': 1, 'c': 3, 'b': 2} # python 3.7之前
od = OrderedDict([('a',1), ('b',2), ('c',3)])
print(od)
# OrderedDict([('a', 1), ('b', 2), ('c', 3)])
OrderedDict
的key是按照插入的顺序排列,不是key本身排序。
在Python 3.7+中,大多数情况下,普通的 dict 能够替换 collections.OrderedDict
。
使用dict时,如果引用不存在的key,就会抛出KeyError。如果希望key不存在时,返回一个默认值,就可以用defaultdict
:
from collections import defaultdict
dd = defaultdict(lambda: 'N/A')
dd['key1'] = 'value1'
print(dd['key1'])
# 'value1'
print(dd['key2'])
# 'N/A'
defaultdict
默认值必须是一个可调用对象或None
想象有如下场景,有一集合 [11,22,33,44,55,66,77,88,99,90...]。需求是将大于60的值保存至字典的第一个key中,将小于60的值保存至第二个key的值中。
原生字典解决方案:
li = [11, 22, 33, 44, 55, 66, 77, 88, 99, 90]
dic = {}
for l in li:
if l > 60:
if dic.has_key('k1'):
dic['k1'].append(l)
else:
dic['k1'] = [l]
if l < 60:
if dic.has_key('k2'):
dic['k2'].append(l)
else:
dic['k2'] = [l]
defaultdict字典解决方案:
from collections import defaultdict
li = [11, 22, 33, 44, 55, 66, 77, 88, 99, 90]
dd = defaultdict(list)
for l in li:
if l > 60:
dd['k1'].append(l)
if l < 60:
dd['k2'].append(l)
Counter
类的目的是用来跟踪值出现的次数。它是一个无序的容器类型,以字典的键值对形式存储,其中元素作为key,其计数作为value。计数值可以是任意的Interger(包括0和负数)。
c = Counter('abcdeabcdabcaba')
print(c)
# Counter({'a': 5, 'b': 4, 'c': 3, 'd': 2, 'e': 1})
Counter 创建的四种方法:
c1 = Counter() # 创建一个空的Counter类
c2 = Counter('gallahad') # 从一个可iterable对象(list、tuple、dict、字符串等)创建
c3 = Counter({'a':4, 'b':2}) # 从一个字典对象创建
c4 = Counter(a=4, b=2) # 从一组键值对创建
当所访问的键不存在时,返回0,而不是KeyError;否则返回它的计数。
c = Counter("abcdefgab")
print(c["a"])
# 2
print(c["c"])
# 1
print(c["h"])
# 0
可以使用一个iterable对象或者另一个Counter对象来更新键值。
计数器的更新包括增加和减少两种。其中,增加使用update()方法:
c = Counter('which')
print(c['h']) # 2
c.update('witch') # 使用另一个iterable对象更新
print(c['h']) # 3
d = Counter('watch')
c.update(d) # 使用另一个Counter对象更新
print(c['h']) # 4
减少则使用subtract()方法:
c = Counter('which')
c.subtract('witch') # 使用另一个iterable对象更新
print(c['h']) # 1
d = Counter('watch')
c.substact(d) # 使用另一个Counter对象更新
print(c['a']) # -1
当计数值为0时,并不意味着元素被删除,删除元素应当使用del
。
c = Counter("abcdcba")
print(c)
# Counter({'a': 2, 'c': 2, 'b': 2, 'd': 1})
c["b"] = 0
print(c)
# Counter({'a': 2, 'c': 2, 'd': 1, 'b': 0})
del c["a"]
print(c)
# Counter({'c': 2, 'b': 2, 'd': 1})
返回一个迭代器。元素被重复了多少次,在该迭代器中就包含多少个该元素。元素排列无确定顺序,个数小于1的元素不被包含。
c = Counter(a=4, b=2, c=0, d=-2)
print(list(c.elements()))
# ['a', 'a', 'a', 'a', 'b', 'b']
返回一个TopN列表。如果n没有被指定,则返回所有元素。当多个元素计数值相同时,排列是无确定顺序的。
c = Counter('abracadabra')
print(c.most_common())
# [('a', 5), ('r', 2), ('b', 2), ('c', 1), ('d', 1)]
print(c.most_common(3))
# [('a', 5), ('r', 2), ('b', 2)]
>>> c = Counter("abcdcba")
>>> c
Counter({'a': 2, 'c': 2, 'b': 2, 'd': 1})
>>> d = c.copy()
>>> d
Counter({'a': 2, 'c': 2, 'b': 2, 'd': 1})
+、-、&、|操作也可以用于Counter。其中&和|操作分别返回两个Counter对象各元素的最小值和最大值。需要注意的是,得到的Counter对象将删除小于1的元素。
>>> c = Counter(a=3, b=1)
>>> d = Counter(a=1, b=2)
>>> c + d # c[x] + d[x]
Counter({'a': 4, 'b': 3})
>>> c - d # subtract(只保留正数计数的元素)
Counter({'a': 2})
>>> c & d # 交集: min(c[x], d[x])
Counter({'a': 1, 'b': 1})
>>> c | d # 并集: max(c[x], d[x])
Counter({'a': 3, 'b': 2})
下面是一些Counter类的常用操作,来源于Python官方文档
sum(c.values()) # 所有计数的总数
c.clear() # 重置Counter对象,注意不是删除
list(c) # 将c中的键转为列表
set(c) # 将c中的键转为set
dict(c) # 将c中的键值对转为字典
c.items() # 转为(elem, cnt)格式的列表
Counter(dict(list_of_pairs)) # 从(elem, cnt)格式的列表转换为Counter类对象
c.most_common()[:-n:-1] # 取出计数最少的n个元素
c += Counter() # 移除0和负值
基于Nginx+Supervisord+uWSGI+Django1.11.1+Python3.6.5构建