导语:collections是实现了特定目标的容器,以提供Python标准内建容器 dict,list,set, tuple 的替代选择。为了让大家更好的认识,本文详细总结collections的相关知识,一起学习吧!
collections 模块:实现特定目标的容器,以提供Python标准内建容器 dict,list,set,tuple 的替代选择
Counter:字典的子类,提供了可哈希对象的计数功能。
defaultdict:字典的子类,提供了一个工厂函数,为字典查询提供了默认值。
OrderedDict:字典的子类,保留了他们被添加的顺序。
namedtuple:创建命名元组子类的工厂函数。
deque:类似列表容器,实现了在两端快速添加(append)和弹出(pop)。
ChainMap:类似字典的容器类,将多个映射集合到一个视图里面。
Counter
Counter 是一个dict子类,主要是用来对你访问的对象频率进行计数
import collections
# 统计字符出现的次数
print collections.Counter("hello world")
>>> Counter({'l': 3, 'o': 2, 'h': 1, 'e': 1, ' ': 1, 'w': 1, 'r': 1, 'd': 1})
# 统计单词个数
print collections.Counter("hello world hello lucy".split())
>>> Counter({'hello': 2, 'world': 1, 'lucy': 1})
常用方法:
- elements():返回一个迭代器,每个元素重复计算的个数,如果一个元素的计数小于1,就会被忽略。
- most_common([n]):返回一个列表,提供n个访问频率最高的元素和计数。
- subtract([iterable-or-mapping]):从迭代对象中减去元素,输入输出可以是0或者负数。
- update([iterable-or-mapping]):从迭代对象计数元素或者从另一个映射对象(或计数器)添加。
c = collections.Counter("hello world hello lucy".split())
print c
>>> Counter({'hello': 2, 'world': 1, 'lucy': 1})
# 获取指定对象的访问次数,也可以使用get方法
print c["hello"]
>>> 2
# 查看元素
print list(c.elements())
>>> ['hello', 'hello', 'world', 'lucy']
c1 = collections.Counter("hello world".split())
c2 = collections.Counter("hello lucy".split())
print c1
>>> ['hello', 'hello', 'world', 'lucy']
print c2
>>> Counter({'hello': 1, 'world': 1})
# 追加对象,+ 或者 c1.update(c2)
print c1+c2
>>> Counter({'hello': 2, 'world': 1, 'lucy': 1})
# 减少对象,- 或者 c1.subtract(c2)
print c1 - c2
>>> Counter({'world': 1})
# 清除
c.clear()
print c
>>> Counter()
defaultdict
返回一个新的类似字典的对象,defaultdict 是内置 dict 类的子类
class collections.defaultdict([default_factory[,...]])
d = collections,defaultdict()
print d
>>> defaultdict(None, {})
e = collections.defaultdict(str)
print e
>>> defaultdict(<class 'str'>, {})
例子
defaultdict 的一个典型用法是使用其中一个内置类型(如str, int, list, dict等)作为默认工厂,这些内置类型在没有参数调用时返回空类型。
e = collections.defaultdict(str)
print e
>>> defaultdict(<class 'str'>, {})
print e["hello"]
>>> ''
# 普通字典调用不存在的键时,报错
e1 = {}
print e1["hello"]
>>>Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: "hello"
使用int作为default_factory
fruit = collections.defaultdict(int)
fruit["apple"] = 2
print fruit
>>> defaultdict(<class 'int'>, {"apple": 2})
print fruit["banana"] # 没有对象时,返回0
>>> 0
print fruit
>>> defaultdict(<class 'int'>, {'apple':2, 'banana': 0})
使用list作为default_factory
s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
d = collections.defaultdict(list)
for k, v in s:
d[k].append(v)
print d
>>> defaultdict(<class 'list'>, {'yellow': [1, 3], 'blue': [2, 4], 'red': [1]})
print d.items()
>>> dict_items([('yellow', [1, 3]), ('blue', [2, 4]), ('red', [1])])
print sorted(d.items())
>>> [('bule', [2, 4]), ('red', [1]), ('yellow', [1, 3])]
使用dict作为default_factory
nums = collections.defaultdict(dict)
nums[1] = {'one': 1}
print nums
>>> defaultdict(<class 'dict'>, {1: {'one': 1}})
print nums[2]
>>> {}
print nums
>>> defaultdict(<class> 'dict', {1: {'one': 1}, 2: {}})
使用set作为default_factory
types = collections.defaultdict(set)
types['手机'].add('华为')
types['手机'].add('小米')
types['显示器'].add('AOC')
print types
>>> defaultdict(<class 'set'>, {'手机': {'华为', '小米'}, '显示器':{’AOC‘}})
OrderDict
Python 字典中的键的顺序是任意的,它们不受添加顺序的控制
collections.OrderedDict 类提供了保留他们添加顺序性的字典对象
o = collections.OrderedDict()
o['k1'] = 'v1'
o['k3'] = 'v3'
o['k2'] = 'v2'
print o
>>> OrderdDict([('k1', 'v1'), ('k3', 'v3'), ('v2', 'k2')])
如果在已经存在的key上添加新的值,将会保留原来key的位置,然后覆盖value的值。
o['k1'] = 666
print o
>>> OrderedDict([('k1', 666), ('k3', 'v3'), ('k2', 'v2')])
print dict(o)
>>> {'k1': 666,'k3': 'v3', 'k2': 'v2'}
namedtuple
三种定义命名元组的方法: 第一个参数是命名元组的构造器(如下:Person1, Person2, Person3)
P1 = collections.namedtuple('Person1', ['name', 'age', 'height'])
P2 = collections.namedtuple('Person2', 'name, age, height')
P3 = collections.namedtuple('Person3', 'name age height')
实例化命名元组
lucy = P1('lucy', 23, 180)
print lucy
>>> Person1(name='lucy', age=23, height=180)
jack = P2('jack', 20, 190)
print jack
>>> Person2(name='jack', age=20, height=190)
print lucy.name
>>> 'lucy'
print jack.age
>>> 20
deque
collections.deque 返回一个新的双向队列对象,从左到右初始化(用方法append()),从iterable(迭代对象)数据创建。如果iterable没有指定,新队列为空。
collections.deque 队列支持线程安全,对于从两端添加(append)或者弹出(pop),复杂度O(1)。
虽然 list 对象也支持类似操作,但是这里优化了定长操作(pop(0),insert(0,v))的开销。
如果maxlen没有指定或者是None,deque可以增长 任意长度。否则,deque就限定到指定最大长度。一旦限定长度得到deque满了,当新项加入时,同样数量的项就从另一端弹出。
支持的方法:
- append(x):添加x到右端。
- appendleft(x):添加x到左端。
- clear():清除所有元素,长度变为0。
- copy():创建一份浅拷贝。
- count(x):计算队列中个数等于x的元素。
- extend(iterable):在队列右侧添加iterable中的元素。
- extendleft(iterable):在队列左侧添加iterable中的元素,注:在左侧添加时,iterable参数的顺序将会反过来添加。
- index(x[, start[, stop]]):返回第x个元素(从start开始计算,在stop之前)。返回第一个匹配,如果没找到的话,抛出ValueError。
- insert(i, x):在位置 i 插入 x 。注:如果插入会导致一个限长 deque 超出长度maxlen的话。就抛出一个IndexError。
- pop():移除最右侧的元素。
- popleft():移除最左侧的元素。
- remove(value):移除找到的第一个value。没有就抛出ValueError。
- reverse():将deque逆序排列,返回None。
- maxlen:队列的最大长度,没有限定则为None。
d = collections.deque(maxlen=10)
print d
>>> deque([], maxlen=10)
d.extend('python')
print [i.upper() for i in d]
['P', 'Y', 'T', 'H', 'O', 'N']
d.append('e')
d.appendleft('f')
d.appendleft('g')
d.appendleft('h')
print d
>>> deque(['h', 'g', 'f', 'p', 'y', 't', 'h', 'o', 'n', 'e'], maxlen=10)
d.appendleft('i')
print d
>>> deque(['i', 'h', 'g', 'f', 'p', 'y', 't', 'h', 'o', 'n'], maxlen=10)
d.append('m')
print d
>>> deque(['h', 'g', 'f', 'p', 'y', 't', 'h', 'o', 'n', 'm'], maxlen=10)
ChainMap
问题背景是我们有多个字典或者映射,想要把它们合并成为一个单独的映射,有人说可以用update进行合并,这样做的问题就是新建了一个数据结构以至于当我们对原来的字典进行更改的时候不会同步。如果想建立一个同步的查询方法,可以使用ChainMap。
可以用来合并两个或多个字典,当查询的时候,从前往后依次查询。简单使用:
d1 = {'apple':1, 'banana':2}
d2 = {'orange':2, 'apple':3, 'pike':1}
combined1 = collections.ChainMap(d1, d2)
combined2 = collections.ChainMap(d2, d1)
print combined1
>>> ChainMap({'apple': 1, 'banana': 2}, {'orange': 2, 'apple':3, 'pike': 1})
print combined2
>>> ChainMap({'orange':2, 'apple':3, 'pike':1}, {'apple':1, 'banana':2})
for k, v in combined1.items():
print(k, v)
>>> orange 2
>>> apple 1
>>> pike1
>>> banana 2
for k, v in combined2.items():
print(k, v)
>>> apple 3
>>> banana 2
>>> orange 2
>>> pike 1
有一个注意点就是当对ChainMap进行修改的时候总是会对第一个字典进行修改,如果第一个字典不在键,则会添加。
d1 = {'apple': 1, 'banana': 2}
d2 = {'orange': 2, 'apple': 3, 'pike': 1}
c = collections.ChainMap(d1, d2)
print c
>>> ChainMap({'apple': 1, 'banana': 2}, {'orange': 2, 'apple': 3, 'pike': 1})
print c['apple']
>>> 1
c['apple'] = 2
print c
>>> ChainMap({'apple': 2, 'banana': 2}, {'orange': 2, 'apple': 3, 'pike': 1})
print c['pike']
>>> 1
c['pike'] = 3
print c
>>> ChainMap({'apple': 2, 'banana': 2, 'pike': 3}, {'orange': 2, 'apple': 3, 'pike': 1})
从原理上讲,ChainMap实际上是把字典存储在一个队列中,当进行字典的增加删除等操作只会在第一个字典上进行,当进行查找的时候会依次查找,new_child()方法实质上是在列表的第一个元素前放入一个字典,默认是{},而parents 是去掉了列表开头的元素。
a = collections.ChainMap()
a['x'] = 1
print a
>>> ChainMap({'x': 1})
b = a.new_child()
print b
>>> ChainMap([], {'x': 1})
b['x'] = 2
print b
>>> ChainMap({'x': 2}, {'x': 1})
b['y'] = 3
print b
>>> ChainMap({'x': 2, 'y': 3}, {'x': 1})
print a
>>> ChainMap({'x': 1})
c = a.new_child()
print c
>>> ChainMap({}, {'x': 1})
c['x'] = 1
c['y'] = 1
print c
>>> ChainMap({'x': 1, 'y': 1}, {'x': 1})
d = c.parents
print d
>>> ChainMap({'x': 1})
print d is a
>>> False
print d == a
>>> True
a = {'x': 1, 'z': 3}
b = {'y': 2, 'z': 4}
c = collections.ChainMap(a, b)
print c
>>> ChainMap({'x': 1, 'z': 3}, {'y': 2, 'z': 4})
print c.parents
>>> ChainMap({'y': 2, 'z': 4})
print c.parents.maps
>>> [{'y': 2, 'z': 4}]
print c.parents.parents
>>> ChainMap({})
网友评论