全文学习参考。
这个模块实现了特定目标的容器,提供了Python标准内建容器 dict , list , set , 和 tuple 的替代选择。
模块中包括以下对象:
collections模块学习
ChainMap对象
一个 ChainMap 类是为了将多个映射快速的链接到一起,这样它们就可以作为一个单元处理。它通常比创建一个新字典和多次调用 update() 要快很多。ChainMap支持常用的字典方法,另外包括maps属性,一个创建上下文的方法new_child以及一个存取收个映射的属性parents.
baseline = {
'music': 'bach', 'art': 'rembrandt'}
adjustments = {
'art': 'van gogh', 'opera': 'carmen'}
c = collections.ChainMap(baseline, adjustments)
print(c) #等价于c.maps
>> ChainMap({
'music': 'bach', 'art': 'rembrandt'}, {
'art': 'van gogh', 'opera': 'carmen'})
c = c.new_child({
'human':'dav'}) #等价于collections.ChainMap({'human':'dav'}, *c.maps)
print(c)
>>ChainMap({
'human': 'dav'}, {
'art': 'van gogh', 'opera': 'carmen'}, {
'music': 'bach', 'art': 'rembrandt'})
print(c.parents) #属性返回一个新的 ChainMap 包含所有的当前实例的映射(除了第一个)。等价于 ChainMap(*c.maps[1:])
>>ChainMap({
'art': 'van gogh', 'opera': 'carmen'}, {
'music': 'bach', 'art': 'rembrandt'})
注意,一个 ChainMap() 的迭代顺序是通过从后往前扫描所有映射来确定的,对于常用的字典方法,ChainMap对象也是支持的:
baseline = {
'music': 'bach'}
adjustments = {
'art': 'van gogh', 'opera': 'carmen'}
per = {
'art': 'wuwu'}
c = collections.ChainMap(adjustments,baseline,per)
c.update({
"art":"beat"}) # 如果不指定,则会对找到的第一个字典进行修改,如果没找到,则会在第一个字典(maps[0])中进行更新。
print(c)
>>ChainMap({
'art': 'beat', 'opera': 'carmen'}, {
'music': 'bach'}, {
'art': 'wuwu'})
c.maps[2].update({
"art":"hua"}) #指定字典则会对指定的字典进行修改
>>ChainMap({
'art': 'beat', 'opera': 'carmen'}, {
'music': 'bach'}, {
'art': 'hua'})
用 ChainMap 类模拟嵌套上下文的例子:
baseline = {
'music': 'bach'}
adjustments = {
'art': 'van gogh', 'opera': 'carmen'}
c = collections.ChainMap(adjustments,baseline)
d = c.new_child({
"qiji": "xiwang"}) # Create nested child context
e = c.new_child() # Child of c, independent from d
print(d.maps[0])
>>{
'qiji': 'xiwang'}
print(e.maps[0] ) # 类似于局部变量,输出当前上下文
>>{
}
print(e.maps[-1] ) # 类似于全局变量,返回源上下文
>>{
'music': 'bach'}
print(e.parents)
>>ChainMap({
'art': 'van gogh', 'opera': 'carmen'}, {
'music': 'bach'})
print(d.parents)
>>ChainMap({
'art': 'van gogh', 'opera': 'carmen'}, {
'music': 'bach'})
同时也可以通过定义子类,来对ChainMap进行修改,实现深度写与删除。
class DeepChainMap(collections.ChainMap):
'Variant of ChainMap that allows direct updates to inner scopes'
def __setitem__(self, key, value):
for mapping in self.maps:
if key in mapping:
mapping[key] = value
return
self.maps[0][key] = value
def __delitem__(self, key):
for mapping in self.maps:
if key in mapping:
del mapping[key]
return
raise KeyError(key)
d = DeepChainMap({
'zebra': 'black'}, {
'elephant': 'blue','snake' : 'green' }, {
'lion': 'yellow'})
d['lion'] = 'orange' # 跟新已存在的
d['snake'] = 'red' # 跟新已存在的
d['cat'] = 'black' # 加入不存在的,默认加入第一映射
del d['elephant'] #删除
print(d)
>>DeepChainMap({
'zebra': 'black', 'cat': 'black'}, {
'snake': 'red'}, {
'lion': 'orange'})
Counter对象
一个计数器工具,提供快速和方便的计数。 Counter 是一个 dict 的子类,用于计数可哈希对象。
c = collections.Counter() # 空计数器
c = collections.Counter('gallahad') #迭代计算各个元素
c = collections.Counter({
'red': 4, 'blue': 2}) #初始化映射
c = collections.Counter(cats=4, dogs=8) #初始化关键字
>>
Counter()
Counter({
'a': 3, 'l': 2, 'g': 1, 'h': 1, 'd': 1})
Counter({
'red': 4, 'blue': 2})
Counter({
'dogs': 8, 'cats': 4})
Counter对象有一个字典接口,如果引用的键没有任何记录,就返回一个0,而不是弹出一个 KeyError :
c = collections.Counter(['eggs', 'ham'])
print(c)
>>Counter({
'eggs': 1, 'ham': 1})
print(c['hat'])
>> 0
del c['ham'] #删除一个计数,不是让他等于0,而是del命令
print(c)
>>Counter({
'eggs': 1})
除去字典方法以外,还有三个其他的方法: elements() 返回一个迭代器,元素按首次出现顺序重复返回。most_common([n]) 返回一个列表,包含n个最常见的元素以及出现次数。subtract([iterable-or-mapping]) 从迭代对象或者映射对象中减去(更新)元素,输入输出可为负数。
c = collections.Counter(a=4, b=2, c=0, d=-2)
d = collections.Counter(a=1, b=2, c=3, d=4)
print(sorted(c.elements()))
>>['a', 'a', 'a', 'a', 'b', 'b']
print(c.most_common(2))
>>[('a', 4), ('b', 2)]
c.subtract(d) #本地修改
print(c)
>>Counter({
'a': 3, 'b': 0, 'c': -3, 'd': -6})
c = c.subtract(d)
print(c)
>> None
常见的使用方法:
c = collections.Counter(a=4, b=2,c = -2)
d = collections.Counter(a=1, b=2, c=3)
print(list(c))
>>['a', 'b', 'c']
print(set(c)) #返回一个集合
>>{
'c', 'b', 'a'}
print(dict(c))
>>{
'a': 4, 'b': 2, 'c': -2}
print(c.items())
>>dict_items([('a', 4), ('b', 2), ('c', -2)])
print(collections.Counter(dict(c))) #构造成对字典的counter
>>Counter({
'a': 4, 'b': 2, 'c': -2})
print(c.most_common()[:-3:-1]) #[:-n-1:-1],返回倒数n个元素
>>[('c', -2), ('b', 2)]
#运算符操作
print(c+d) #加法,结果保留正数
>>Counter({
'a': 5, 'b': 4, 'c': 1})
print(c - d) #减法,结果保留正数
>>Counter({
'a': 3})
print(c & d) #交集:min(c[x],d[x])
>>Counter({
'b': 2, 'a': 1})
print(c | d) #并集:max(c[x],d[x])
>>Counter({
'a': 4, 'c': 3, 'b': 2})
deque 对象
返回一个新的双向队列对象,从左到右初始化(用方法 append()) ,从 iterable (迭代对象) 数据创建。
支持如下方法:
append(x):添加x到右端。
appendleft(x):添加 x 到左端。
clear():移除所有元素,使其长度为0。
copy():创建一份浅拷贝。
count(x):计算 deque 中元素等于 x 的个数。
d = collections.deque('http')
for elem in d: # 迭代操作元素
print(elem.upper())
>> H T T P
d.append('j')
>> deque(['h', 't', 't', 'p', 'j'])
d.appendleft('c')
>>deque(['c', 'h', 't', 't', 'p', 'j'])
d.pop()
>>j
d.popleft()
>>c
d[0]
>>h
##以下均初始化 d = collections.deque('http')
list((d))
>> ['h', 't', 't', 'p']
list(reversed(d))
>> ['p', 't', 't', 'h']
d.extend('jkl')
>>deque(['h', 't', 't', 'p', 'j', 'k', 'l'])
d.rotate(1) #向右旋转1
>>deque(['p', 'h', 't', 't'])
d.rotate(1) #向左旋转1
>>deque(['t', 't', 'p', 'h'])
d.clear() #清空队列
d.pop() #清空后无法输出 报错
d.extendleft('abc') #左边开始拓展
>>deque(['c', 'b', 'a', 'h', 't', 't', 'p'])
常用方法:
## 用来删除第n个元素 del d[n]
def delete_nth(d, n):
d.rotate(-n)
d.popleft()
d.rotate(n)
defaultdict 对象
返回一个新的类似字典的对象。 defaultdict 是内置 dict 类的子类。 它重载了一个方法并添加了一个可写的实例变量。
本对象包含一个名为 default_factory 的属性,构造时,第一个参数用于为该属性提供初始值,默认为 None。所有其他参数(包括关键字参数)都相当于传递给 dict 的构造函数。
使用 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.items())
>>dict_items([('yellow', [1, 3]), ('blue', [2, 4]), ('red', [1])])
#等价于以下dict操作,但是速度更快,更简单。
d = {
}
for k, v in s:
d.setdefault(k, []).append(v)
设置 default_factory 为 int,使 defaultdict 用于计数:
s = 'mississippi'
d = collections.defaultdict(int)
for k in s:
d[k] += 1 #它会查询失败,则 default_factory 会调用 int() 来提供一个整数 0 作为默认值。
print(d)
>>defaultdict(<class 'int'>, {
'm': 1, 'i': 4, 's': 4, 'p': 2})
函数 int() 总是返回 0,这是常数函数的特殊情况。一个更快和灵活的方法是使用 lambda 函数,可以提供任何常量值(不只是0):
def constant_factory(value):
return lambda: value
d = collections.defaultdict(constant_factory('<missing>'))
d.update(name='John', action='ran')
print('%(name)s %(action)s to %(object)s' % d)
>>John ran to <missing>
设置 default_factory 为 set 使 defaultdict 用于构建 set 集合:
s = [('red', 1), ('blue', 2), ('red', 3), ('blue', 4), ('red', 1), ('blue', 4)]
d = collections.defaultdict(set)
for k, v in s:
d[k].add(v)
print(d.items())
>>dict_items([('red', {
1, 3}), ('blue', {
2, 4})])
namedtuple() 命名元组的工厂函数
命名元组赋予每个位置一个含义,提供可读性和自文档性。它们可以用于任何普通元组,并添加了通过名字获取值的能力,通过索引值也是可以的。
Point = collections.namedtuple('Point', ['x', 'y'])
p = Point(11,12)
print(p)
>>Point(x=11, y=12)
print(p[0] + p[1])
>>23
x,y = p #x=11,y=12 #像常规元组一样解包
print(p.x + p.y) #字段也可以通过名称访问
>>23
print(p)
>>Point(x=11, y=12)
_make() 方法构建新的实例,_asdict() 方法返回一个字典映射。
Point = collections.namedtuple('Point', ['x', 'y'])
t = [11, 22]
p = Point._make(t)
print(p)
>>Point(x=11, y=22)
p = Point._asdict(p)
print(p)
>>{
'x': 11, 'y': 22}
_replace(kwargs) 返回一个新的命名元组实例,并将指定域替换为新的值,_fields属性返回元组字段名,_field_defaults**字典将字段名称映射到默认值。:
Point = collections.namedtuple('Point', ['x', 'y'])
p = Point(x = 11,y = 22)
p = p._replace(x = 33)
print(p)
>>Point(x=33, y=22)
print(p._fields)
>>('x', 'y')
Point = collections.namedtuple('Point', ['x', 'y'],defaults=[0,0])
p = Point(x=11,y=23)
print(p._field_defaults)
>>{
'x': 0, 'y': 0}
OrderedDict 对象
有序词典就像常规词典一样,但有一些与排序操作相关的额外功能。
class collections.OrderedDict([items]) 返回一个 dict 子类的实例,它具有专门用于重新排列字典顺序的方法。
popitem(last=True) 移除并返回一个 (key, value) 键值对, 如果 last 值为真,则按 LIFO 后进先出的顺序返回键值对,否则就按 FIFO 先进先出的顺序返回键值对。
move_to_end(key, last=True) 将现有 key 移动到有序字典的任一端。 如果 last 为真值(默认)则将元素移至末尾;如果 last 为假值则将元素移至开头。如果 key 不存在则会触发 KeyError:
d = collections.OrderedDict.fromkeys('abcde')
print(d)
>>OrderedDict([('a', None), ('b', None), ('c', None), ('d', None), ('e', None)])
d.move_to_end('b')
print(''.join(d.keys()))
>>acdeb
print(d.popitem())
>>('b', None)
常见用法:
创建记住键值 最后 插入顺序的有序字典变体很简单。 如果新条目覆盖现有条目,则原始插入位置将更改并移至末尾:
class LastUpdatedOrderedDict(collections.OrderedDict):
'Store items in the order the keys were last added'
def __setitem__(self, key, value):
super().__setitem__(key, value)
self.move_to_end(key)
d = LastUpdatedOrderedDict.fromkeys('abcdeda')
print(d)
>>LastUpdatedOrderedDict([('b', None), ('c', None), ('e', None), ('d', None), ('a', None)])