collections
namedtuple
例如表示一个二维坐标,p = (1, 2)
很难看出是一个坐标,定义一个class
又小题大做,这时,namedtuple
就派上用场
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])
p = Point(1, 2)
print(p.x)
print(p.y)
1
2
可以验证创建的Point
对象是tuple
的一种子类:
print(isinstance(p, Point))
print(isinstance(p, tuple))
True
True
deque
list
存储数据时是线性存储,deque
是双向链表,适合用于队列和栈:
from collections import deque
q = deque(['a', 'b', 'c'])
q.append('x')
q.appendleft('y')
q
deque(['y', 'a', 'b', 'c', 'x'])
defaultdict
使用dict
时,如果引用的key
不存在,就会抛出一个KeyError
。如果希望key不存在时,返回一个默认值,就可以用defaultdict
:
from collections import defaultdict
dd = defaultdict(lambda: 'N/A')
dd['key1'] = 'abc'
print(dd['key1'])
print(dd['key2']) # 不存在的key,输出默认值
abc
N/A
注意默认值是调用函数返回的,而函数再创建defaultdict
对象时传入
OrderedDict
使用dict
是,key是无序的,如果要保持key的顺序,可以用OrderedDict
:
from collections import OrderedDict
d = dict([('a', 1), ('b', 2), ('c', 3)]) # 无序dict
od = OrderedDict([('a', 1), ('b', 2), ('c', 3)]) # 有序
od
OrderedDict([('a', 1), ('b', 2), ('c', 3)])
注意OrderedDict
的key
会按照插入的顺序排列,而不是key
本身排序。
OrderedDict
可以实现一个FIFO的dict,当容量超出限制时,先删除最早添加的Key:
from collections import OrderedDict
# subclass from OrderedDict
class LastUpdatedOrderedDict(OrderedDict):
def __init__(self, capacity):
super(LastUpdatedOrderedDict, self).__init__()
self._capacity = capacity
def __setitem__(self, key, value):
containsKey = 1 if key in self else 0
if len(self) - containsKey >= self._capacity:
# pop item in FIFO order
last = self.popitem(last=False)
print('remove:', last)
if containsKey:
del self[key]
print('set:', (key, value))
else:
print('add:', (key, value))
OrderedDict.__setitem__(self, key, value)
fifo = LastUpdatedOrderedDict(3)
fifo['a'] = 'a'
fifo['b'] = 'b'
fifo['c'] = 'c'
fifo['d'] = 'd'
add: ('a', 'a')
add: ('b', 'b')
add: ('c', 'c')
remove: ('a', 'a')
add: ('d', 'd')
ChainMap
ChainMap
可以把一组dict
串起来并组成一个逻辑上的dict
。ChainMap
本身也是一个dict
,但是在查找的时候,会按照顺序在内部的dict中依次查找。
ChainMap
和普通字典的区别在于,这个大字典里能保存一样的key,当我们用重复的key
去访问value
的时候得到的一定是在大字典里位置靠前的value
,被链接的字典因为排序的不同而产生优先级。
应用程序往往都需要传入参数,参数可以通过命令行传入,可以通过环境变量传入,还可以有默认参数。我们可以用ChainMap
实现参数的优先级查找,即先查命令行参数,如果没有传入,再查环境变量,如果没有,就使用默认参数。
下面的代码演示了如何查找user
和color
这两个参数
from collections import ChainMap
import os
import argparse
# 构造缺省参数
defaults = {
'color': 'red',
'user': 'guest'
}
# 构造命令行参数
parser = argparse.ArgumentParser()
parser.add_argument('-u', '--user')
parser.add_argument('-c', '--color')
namespace = parser.parse_args()
command_line_args = {k: v for k, v in vars(namespace).items() if v}
# 组合成ChainMap
combined = ChainMap(command_line_args, os.environ, defaults)
# 打印参数:
print('color=%s' % combined['color'])
print('user=%s' % combined['user'])
没有任何参数时,打印出默认参数
$ python3 use_chainmap.py
color=red
user=guest
当传入命令行参数时,优先使用命令行参数:
$ python3 use_chainmap.py -u bob
color=red
user=bob
同时传入命令行参数和环境变量,命令行参数的优先级较高:
$ user=admin color=green python3 use_chainmap.py -u bob
color=green
user=bob
Counter
Counter
是一个简单的计数器,例如,经常用来统计字符出现的个数:
from collections import Counter
c = Counter()
for ch in 'programming':
c[ch] = c[ch] + 1
c
Counter({'p': 1, 'r': 2, 'o': 1, 'g': 2, 'a': 1, 'm': 2, 'i': 1, 'n': 1})
# 直接将字符串作为参数传入
c2 = Counter('abccc')
c2
Counter({'a': 1, 'b': 1, 'c': 3})
# update Counter
c2.update('hello')
c2
Counter({'a': 1, 'b': 1, 'c': 3, 'h': 2, 'e': 2, 'l': 4, 'o': 2})
Counter
是dict
的一个子类,上面的结果可以看出每个字符出现的次数。