这个模块实现了特定目标的容器,提供了python标准内建容器dict, list, set和tuple的替代选择
namedtuple() | 创建命名元组子类的工厂函数 |
deque | 类似列表(list)的容器,实现了在两端快速的添加(append)和弹出(pop) |
ChainMap | 类似字典(dict)的容器类,将多个映射集合到一个视图里面 |
Counter | 字典的子类,提供了可哈希对象的计数功能 |
OrderedDict | 字典的子类,保存了他们被添加的顺序 |
defaultdict | 字典的子类,提供了一个工厂函数,为字典查询提供了一个默认值 |
UserDict | 封装了字典对象,简化了字典子类化 |
UserList | 封装了列表对象,简化了列表子类化 |
UserString | 封装了字符串对象,简化了字符串子类化 |
>>> Point = namedtuple('Point', ['x', 'y'])
>>> p = Point(11, y=22) # 用位置参数或者关键字参数实例化
>>> p[0] + p[1] # 索引取值
33
>>> x,y = p # 解包
>>> x,y
(11, 22)
>>> p.x+p.y # 字段名获取值
33
>>> p # __repr__
Point(x=11, y=22)
返回一个新的元组子类,名为typaname
field_name: 字段名,可以是一个像['x', 'y']一样的字符串序列,也可以是一个纯字符串,用空白或者逗号分隔开元素名,比如‘x y’ 或者‘x, y’
rename:如果为真,无效字段名会自动传换成位置名。比如['abc', 'def', 'abc']转换成[
'abc', '_1', '_2']
defaults: 可以为None,或者是一个默认值的iterable。作为字段默认值出现,如果defaults为iterable,且长度小于字field_name的长度,那么defaults就应用到最右边的参数。比如field_name为['x', 'y', 'z'],default为(1,2),那么x就必须指定一个参数值,y默认值为1,z默认值2.
module: 如果module值有定义,命名元组的__module__属性值就被设置
用于赋值 csv sqlite3 模块返回的元组示例:
EmployeeRecord = namedtuple('EmployeeRecord', 'name, age, title, department, paygrade')
import csv
for emp in map(EmployeeRecord._make, csv.reader(open("employees.csv", "rb"))):
print(emp.name, emp.title)
import sqlite3
conn = sqlite3.connect('/companydata')
cursor = conn.cursor()
cursor.execute('SELECT name, age, title, department, paygrade FROM employees')
for emp in map(EmployeeRecord._make, cursor.fetchall()):
print(emp.name, emp.title)
somenamedtuple._make(iterable)
# 从存在的序列或迭代实例创建一个新实例
somenamedtuple._asdict()
# 返回一个新dict,将值映射到字段名
somenamedtuple._replace(**kwargs)
# 返回一个新的命名元组实例,并将指定域替换为新的值
somenamedtuple._fields
# 列出字段名
somenamedtuple._field_defaults
# 将字段名映射到默认值
>>> t = [11, 22]
>>> Point._make(t) # _make(iterable)
Point(x=11, y=22)
>>> p = Point(x=11, y=22)
>>> p._asdict() # _asdict()
{'x':11, 'y':22}
>>> p._replace(x=33) # _replace(**kwargs)
Point(x=33, y=22)
>>> for partnum, record in inventory.item():
inventory[partnum] = record._replace(price=newprices[partnum], timestamp=time.now())
>>>p._fields # _fields
('x', 'y')
>>> Color = namedtuple('Color', ['red', 'green', 'blue'])
>>> Pixel = namedtuple('Pixel', Point._fields + Color._fields)
>>> Pixel(11, 22, 128, 255, 0)
Pixel(x=11, y=22m red=128, green=255, blue=0)
>>> Account = namedtuple('Account', ['type', 'balance'], defaults=[0])
>>> Account._field_defaults # _field_defaults
{'balance':0}
>>> Account('premium')
Account(type='premium', balance=0)
>>> getattr(p, 'x') # getattr()
11
>>> d = {'x':11, 'y':22}
>>> Point(**d) # 转换字典到一个元组
Point(x=11,y=22)
>>> class Point(namedtuple('Point', ['x', 'y'])):
__slots__ = ()
@property
def hypot(self):
return (self.x **2 + self.y ** 2) ** 0.5
def __str__(self):
return 'Point: x=%6.3f y=%6.3f hypot=%6.3f' % (self.x, self.y, self.hypot())
>>> for p in Point(3,4), Point(14, 5/7):
print(p)
Point: x= 3.000 y= 4.000 hypot= 5.000
Point: x=14.000 y= 0.714 hypot=14.018
>>> Book = namedtuple('Book', ['id', 'title', 'authors']) # 通过__doc__添加说明文档
>>> Book.__doc__ += "Hardcover book in active collection"
>>> Book.id.__doc__ = '13-digit ISBN'
返回一个新的双向队列对象,从左到右初始化(用append()方法),从iterable数据创建,如果iterable没有指定,新队列为空。
如果maxlen没有指定或者是None,则deque可以增长到任意长度,否则,增长到指定长度。一旦限定长度的deque满了,当新项添加时,则相同数量的项从另一端弹出。
append(x)
# 添加x到右端
appendleft(x)
# 添加x到左端
clear()
# 移除所有元素,使其长度为0
copy()
# 创建一个浅拷贝
count(x)
# 计算deque中元素等于x的个数
extend(iterable)
# 扩展deque的右端,通过添加iterable中的元素
extentleft(iterable)
# 扩展deque的左端,通过添加iterable中的元素。但是,添加在左端时,iterable中的元素将会被反过来添加
index(x[,start[,stop]])
# 返回x在deque中的位置(在索引start之后,索引stop之前),返回第一个匹配项,如果未找到,引发ValueError异常
insert(i, x)
# 在位置i中插入x;如果插入x会使限定长度的deque的长度超出maxlen,则引发 IndexError异常
pop()
# 移除deque最右端的元素并返回该元素,如果deque为空,则引发IndexError
popleft()
# 移除deque最左端的元素并返回该元素,如果deque为空,则引发IndexError
remove(value)
# 移除找到第一个value,如果没有,则引发ValueError
reverse()
# 将deque逆序排列,返回None
rotate(n)
# deque向右循环n步,如果n为负数,则向左循环;如果deque不为空,deque每向右循环一步就等价于d.appendleft(d.pop()),deque每向左循环一步就等价于d.append(popleft())
maxlen
# deque提供的一个只读属性,deque的最大尺寸,没有指定则为None
# 注:索引访问两端的复杂度都为O(1), 但在中间则会降低为O(n),如需快速随机访问,请改用列表
def tail(filename, n=3):
"""
限长的deque提供了类似Unix tail的功能
"""
# Return the last n lines of file
with open(filename) as f:
return deque(f, n)
def moving_average(iterable, n=3):
"""
维护一个近期添加元素的序列,通过从右边添加和左边弹出
"""
# moving_average([40, 30, 50, 46, 39, 44]) --> 40.0 42.0 45.0 43.0
# http://en.wikipedia.org/wiki/Moving_average
it = iter(iterable)
d = deque(itertools.islice(it, n-1))
d.appendleft(0)
s = sum(d)
for elem in it:
s += elem - d.popleft()
d.append(elem)
yield s / n
for average in moving_average([40, 30, 50, 46, 39, 44]):
print(average )
def roundrobin(*iterables):
"""
轮询调度器
"""
# roundrobin('ABC', 'D', 'EF') --> A D E B F C"
iterators = deque(map(iter, iterables))
while iterators:
try:
while True:
yield next(iterators[0])
iterators.rotate(-1)
except StopIteration:
# Remove an exhausted iterator.
iterators.popleft()
def delete_nth(d, n):
"""
通过rotate()实现deque切片和删除
"""
d.rotate(-n)
d.popleft()
d.rotate(n)
from collections import ChainMap
a = {"name": "bob"}
b = {"age": 18}
d = ChainMap(a, b)
print(d) # ChainMap({'name': 'bob'}, {'age': 18})
print(d.maps) # [{'name': 'bob'}, {'age': 18}]
b["age"] = 23
print(d) # ChainMap({'name': 'bob'}, {'age': 23})
e = d.new_child()
print(e) # ChainMap({}, {'name': 'bob'}, {'age': 23})
print(e.parents) # ChainMap({'name': 'bob'}, {'age': 23})
e['name'] = 'Ada'
e['age'] = 55
d['name'] = "Alice"
print(e) # ChainMap({'name': 'Ada', 'age': 55}, {'name': 'Alice'}, {'age': 23})
print(e.parents) # ChainMap({'name': 'Alice'}, {'age': 23})
print(d.parents) # ChainMap({'age': 23})
一个ChainMap将多个字典或者其它映射组合在一起,创建一个单独的可更新的视图。如果没有maps被指定,就提供一个默认的空字典,如下示例:
a = ChainMap()
print(a) # ChainMap({})
一个ChainMap通过引用合并底层映射,所以如果一个底层映射更改了,会反映到ChainMap;
a = {"name": "bob"}
b = ChainMap(a)
print(b) # ChainMap({'name': 'bob'})
a['name'] = 'Ada'
print(b) # ChainMap({'name': 'Ada'})
maps
# 属性,一个可以更新的映射列表,至少包含一个映射
new_child(m=None, **kwargs)
# 方法,返回一个新的ChainMap,包含一个新的映射,和当前实例中的所有映射。如果m被指定,它会成为新的映射添加在当前的列表中;如果m为None,调用d.new_chile(),则等价于ChainMap({}, *d.maps)。如 果指定了任何关键字参数,它们则会更新传入的映射或者字典,此方法被用于创建上下文,它可在不改变任何上级映射的前提下更新映射
parents
# 属性返回一个新的ChainMap包含当前实例的所有的映射,除了第一个。一个d.parents等价于ChainMap(*d.maps[1:])
"""
ChainMap只更新第一个映射,通过子类实现ChainMap的深度写和删除
"""
from collections import ChainMap
class DeepChainMap(ChainMap):
def __setitem__(self, key, value):
for elem in self.maps:
if key in elem:
elem[key] = value
return
self.maps[0][key] = value
def __delitem__(self, key):
for elem in self.maps:
if key in elem:
del elem[key]
return
raise KeyError(key)
d = DeepChainMap({'zebra': 'black'}, {'elephant': 'blue'}, {'lion': 'yellow'})
d['lion'] = 'orange' # update an existing key two levels down
d['snake'] = 'red' # new keys get added to the topmost dict
del d['elephant'] # remove an existing key one level down
print(d) # DeepChainMap({'zebra': 'black', 'snake': 'red'}, {}, {'lion': 'orange'})
一个Counter是一个dict的子类,用于计数可哈希对象。它是一个集合,元素像字典键一样存储,它们的计数存储为值。计数可以任何整数值,包括0和负数。
>>> c = Counter() # a new, empty Counter
>>> c = Counter("hello,world") # a new Counter from an iterable
>>> c = Counter({"color":"red", "food":"tomato"}) # a new Counter from a mapping
>>> c = Counter(color="red", food="tomato") # a new Counter from keyword args
如果访问的键,不在Counter, 会返回0
>>> c = Counter("hello,world")
>>> print(c['a']) # 0
移除一个键,需要使用del
c = Counter("hello,world")
del c['h']
print(c) # Counter({'l': 3, 'o': 2, 'e': 1, ',': 1, 'w': 1, 'r': 1, 'd': 1})
elements()
# 返回一个迭代器,其中每个元素将重复出现计数值指定次。元素会按首次出现的顺序返回。如果某个元素计数值小于一,elements()将忽略该元素
most_common([n])
# 返回一个列表,其中包含n个最常见的元素及出现次数,按常见程度由高到低排列。如果n省略为None, 则返回计数器中的所有元素。计数值相当的元素按首次出现的顺序排列;在值需要排序的时候使用
subtract([iterable-or-mapping])
# 从迭代对象或映射对象中减去元素
total()
# 统计总计数值
update([iterable-or-mapping])
# 从迭代对象或映射对象中添加元素
>>> c = Counter("hello")
>>> sorted(c.elements())
['e', 'h', 'l', 'l', 'o']
>>> c.most_common(2)
[('l', 2), ('h', 1)]
>>> d = Counter({'l': 3})
>>> c.subtract(d)
Counter({'h': 1, 'e': 1, 'o': 1, 'l': -1})
>>> c.update(d)
Counter({'l': 2, 'h': 1, 'e': 1, 'o': 1})
>>>list(c)
['h', 'e', 'l', 'o']
>>> set(c)
{'o', 'e', 'h', 'l'}
>>> dict(c)
{'h': 1, 'e': 1, 'l': 2, 'o': 1}
>>> c.items()
dict_items([('h', 1), ('e', 1), ('l', 2), ('o', 1)])
>>> +c # 删除0和负数计数
Counter({'l': 2, 'h': 1, 'e': 1, 'o': 1})
>>> c.clear()
None
提供了几个数学操作,可以结合 Counter 对象,以生产 multisets (计数器中大于0的元素)。 加和减,结合计数器,通过加上或者减去元素的相应计数。交集和并集返回相应计数的最小或最大值。每种操作都可以接受带符号的计数,但是输出会忽略掉结果为零或者小于零的计数。
>>> c = Counter(a=3, b=1)
>>> d = Counter(a=1, b=2)
>>> c + d # add two counters together: c[x] + d[x]
Counter({'a': 4, 'b': 3})
>>> c - d # subtract (keeping only positive counts)
Counter({'a': 2})
>>> c & d # intersection: min(c[x], d[x])
Counter({'a': 1, 'b': 1})
>>> c | d # union: max(c[x], d[x])
Counter({'a': 3, 'b': 2})
有序字典比常规字典更擅长排序,是个需要频繁排序的操作
返回一个dict的子类,它具有了专门用于重新排列字典顺序的方法
popitem(last=True)
# 移除并返回一对(key,value)键值对;如果last为真,则按照LIFO后进先出的顺序返回键值对,否则,按照FIFO先进先出
move_to_end(key, last=True)
# 将已存在的key移到OrderDict的一端,如果last为True,则移动到最右端,如果last为False,则移动的开端;如果key不存在,则抛出KeyError
返回一个新的类似字典的对象,defaultdict是内置dict的子类。它重载了一个方法并添加了一个可写的实例变量
本对象包含一个名为default_factory的属性。构造defaultdict对象是,传入的第一个参数会被设为default_factory的初始值,如果没传,默认为None。其他所有参数(包括关键字参数)都相当于传给dict的构造函数。
__missing__(key)
# 如果default_factory为None,调用该方法会抛出KeyError异常,附带参数key
# 如果default_factory不为None,则它会被(不带参数)调来为key提供一个默认值,这个值和key作为一对键值对插入到字典中,并作为本方法的返回值返回
# 如果调用default_factory的过程中出现异常,这个异常会被原封不动的向外层传递
# 在无法找到所需键值对时,本方法会被dict的__getitem__()方法调用。无论本方法返回了值还是抛出了异常,都会被__getitem__()传递
# 注意,__missing__()不会被除__getitem__()以外的方法调用。意味着get()会像正常的dict返回None,而不是default_factory
default_factory
# 本属性由__missig__()方法调用。
"""
使用defaultdict,将一个(键-值对)序列转化为(键-列表)字典
"""
from collections import defaultdict
s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
d = defaultdict(list)
for k, v in s:
d[k].append(v)
print(d)
# defaultdict(, {'yellow': [1, 3], 'blue': [2, 4], 'red': [1]})
"""
default_factory设置为int, 使defaultdict用于计数
"""
from collections import defaultdict
s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
d = defaultdict(int)
for k, v in s:
d[k] += v
print(d) # defaultdict(, {'yellow': 4, 'blue': 6, 'red': 1})
"""
使用lamdba函数,更灵活的提供默认值
"""
def constant_factory(value):
return lambda: value
d = defaultdict(constant_factory(''))
d.update(name='John', action='ran')
e = '%(name)s %(action)s to %(object)s' % d
print(e) # John ran to
"""
设置 default_factory 为 set 使 defaultdict 用于构建 set 集合
"""
s = [('red', 1), ('blue', 2), ('red', 3), ('blue', 4), ('red', 1), ('blue', 4)]
d = defaultdict(set)
for k, v in s:
d[k].add(v)
print(sorted(d.items())) # [('blue', {2, 4}), ('red', {1, 3})]
UserDict类用作字典对象的外包装,如果想要对dict的功能进行扩展,可以使用此类。
collections.
UserDict
([initialdata])模拟字典的类。 这个实例的内容保存在一个常规字典中,它可以通过 UserDict 实例的 data 属性来访问。 如果提供了 initialdata,则 data 会用其内容来初始化;请注意对 initialdata 的引用将不会被保留,以允许它被用于其他目的。
UserDict实例支持的属性:
data
# 一个真实的字典,用于保存 UserDict 类的内容。
这个类封装了列表对象。它是一个有用的基础类,对于你想自定义的类似列表的类,可以继承和覆盖现有的方法,也可以添加新的方法。这样我们可以对列表添加新的行为。
对这个类的需求已部分由直接创建 list 的子类的功能所替代;不过,这个类处理起来更容易,因为底层的列表可以作为属性来访问。
collections.
UserList
([list]) 模拟一个列表。这个实例的内容被保存为一个正常列表,通过 UserList 的 data 属性存取。实例内容被初始化为一个 list 的copy,默认为 []
空列表。 list 可以是迭代对象,比如一个Python列表,或者一个 UserList 对象;
UserList实例支持的属性:
data
# 一个 list 对象用于存储 UserList 的内容。
子类化的要求: UserList 的子类需要提供一个构造器,可以无参数调用,或者一个参数调用。返回一个新序列的列表操作需要创建一个实现类的实例。它假定了构造器可以以一个参数进行调用,这个参数是一个序列对象,作为数据源。
如果一个分离的类不希望依照这个需求,所有的特殊方法就必须重写;请参照源代码进行修改。
UserString 类是用作字符串对象的外包装。对这个类的需求已部分由直接创建 str 的子类的功能所替代;不过,这个类处理起来更容易,因为底层的字符串可以作为属性来访问。
collections.
UserString
(seq) 模拟一个字符串对象。这个实例对象的内容保存为一个正常字符串,通过 UserString 的 data 属性存取。实例内容初始化设置为 seq 的copy。seq 参数可以是任何可通过内建 str() 函数转换为字符串的对象。
UserString 提供了以下属性作为字符串方法和操作的额外支持:
data
# 一个真正的 str 对象用来存放 UserString 类的内容。
在 3.5 版更改: 新方法 __getnewargs__
, __rmod__
, casefold
, format_map
, isprintable
, 和 maketrans
。