常用模块
collections
该模块实现了专门的容器数据类型,为 Python 的通用内置容器、dict、list、set 和 tuple 提供了替代方案。
用于创建具有命名字段的元组子类的工厂函数 |
|
类似列表的容器,两端具有快速追加和弹出 |
|
用于创建多个映射的单个视图的类 dict 类 |
|
用于计算可散列对象的 dict 子类 |
|
添加了记住订单条目的 dict 子类 |
|
dict 子类调用工厂函数来提供缺失值 |
|
围绕字典对象的包装器,以便于 dict 子类化 |
|
围绕列表对象的包装器,以便于列表子类化 |
|
围绕字符串对象的包装器,以便于字符串子类化 |
collections是Python内建的一个集合模块,提供了许多有用的集合类。
namedtuple
我们知道tuple
可以表示不变集合,例如,一个点的二维坐标就可以表示成:
>>> p = (1, 2)
但是,看到(1, 2)
,很难看出这个tuple
是用来表示一个坐标的。
定义一个class又小题大做了,这时,namedtuple
就派上了用场:
>>> from collections import namedtuple
>>> Point = namedtuple('Point', ['x', 'y'])
>>> p = Point(1, 2)
>>> p.x
1
>>> p.y
2
namedtuple
是一个函数,它用来创建一个自定义的tuple
对象,并且规定了tuple
元素的个数,并可以用属性而不是索引来引用tuple
的某个元素。
这样一来,我们用namedtuple
可以很方便地定义一种数据类型,它具备tuple的不变性,又可以根据属性来引用,使用十分方便。
可以验证创建的Point
对象是tuple
的一种子类:
>>> isinstance(p, Point)
True
>>> isinstance(p, tuple)
True
类似的,如果要用坐标和半径表示一个圆,也可以用namedtuple
定义:
# namedtuple('名称', [属性list]):
Circle = namedtuple('Circle', ['x', 'y', 'r'])
deque
使用list
存储数据时,按索引访问元素很快,但是插入和删除元素就很慢了,因为list
是线性存储,数据量大的时候,插入和删除效率很低。
deque是为了高效实现插入和删除操作的双向列表,适合用于队列和栈:
>>> from collections import deque
>>> q = deque(['a', 'b', 'c'])
>>> q.append('x')
>>> q.appendleft('y')
>>> q
deque(['y', 'a', 'b', 'c', 'x'])
deque
除了实现list的append()
和pop()
外,还支持appendleft()
和popleft()
,这样就可以非常高效地往头部添加或删除元素。
defaultdict
使用dict
时,如果引用的Key不存在,就会抛出KeyError
。如果希望key不存在时,返回一个默认值,就可以用defaultdict
:
>>> from collections import defaultdict
>>> dd = defaultdict(lambda: 'N/A')
>>> dd['key1'] = 'abc'
>>> dd['key1'] # key1存在
'abc'
>>> dd['key2'] # key2不存在,返回默认值
'N/A'
注意默认值是调用函数返回的,而函数在创建defaultdict
对象时传入。
除了在Key不存在时返回默认值,defaultdict
的其他行为跟dict
是完全一样的。
OrderedDict
使用dict
时,Key是无序的。在对dict
做迭代时,我们无法确定Key的顺序。
如果要保持Key的顺序,可以用OrderedDict
:
>>> from collections import OrderedDict
>>> d = dict([('a', 1), ('b', 2), ('c', 3)])
>>> d # dict的Key是无序的
{'a': 1, 'c': 3, 'b': 2}
>>> od = OrderedDict([('a', 1), ('b', 2), ('c', 3)])
>>> od # OrderedDict的Key是有序的
OrderedDict([('a', 1), ('b', 2), ('c', 3)])
注意,OrderedDict
的Key会按照插入的顺序排列,不是Key本身排序:
>>> od = OrderedDict()
>>> od['z'] = 1
>>> od['y'] = 2
>>> od['x'] = 3
>>> list(od.keys()) # 按照插入的Key的顺序返回
['z', 'y', 'x']
OrderedDict
可以实现一个FIFO(先进先出)的dict,当容量超出限制时,先删除最早添加的Key:
from collections import OrderedDict
class LastUpdatedOrderedDict(OrderedDict):
<span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self, capacity)</span>:</span>
super(LastUpdatedOrderedDict, self).__init__()
self._capacity = capacity
<span class="function"><span class="keyword">def</span> <span class="title">__setitem__</span><span class="params">(self, key, value)</span>:</span>
containsKey = <span class="number">1</span> <span class="keyword">if</span> key <span class="keyword">in</span> self <span class="keyword">else</span> <span class="number">0</span>
<span class="keyword">if</span> len(self) - containsKey >= self._capacity:
last = self.popitem(last=<span class="built_in">False</span>)
print(<span class="string">'remove:'</span>, last)
<span class="keyword">if</span> containsKey:
<span class="keyword">del</span> self[key]
print(<span class="string">'set:'</span>, (key, value))
<span class="keyword">else</span>:
print(<span class="string">'add:'</span>, (key, value))
OrderedDict.__setitem__(self, key, value)
ChainMap
ChainMap
可以把一组dict
串起来并组成一个逻辑上的dict
。ChainMap
本身也是一个dict,但是查找的时候,会按照顺序在内部的dict依次查找。
什么时候使用ChainMap
最合适?举个例子:应用程序往往都需要传入参数,参数可以通过命令行传入,可以通过环境变量传入,还可以有默认参数。我们可以用ChainMap
实现参数的优先级查找,即先查命令行参数,如果没有传入,再查环境变量,如果没有,就使用默认参数。
下面的代码演示了如何查找user
和color
这两个参数:
from collections import ChainMap
import os, 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({'g': 2, 'm': 2, 'r': 2, 'a': 1, 'i': 1, 'o': 1, 'n': 1, 'p': 1})
>>> c.update('hello') # 也可以一次性update
>>> c
Counter({'r': 2, 'o': 2, 'g': 2, 'm': 2, 'l': 2, 'p': 1, 'a': 1, 'i': 1, 'n': 1, 'h': 1, 'e': 1})
Counter
实际上也是dict
的一个子类,上面的结果可以看出每个字符出现的次数。
小结
collections
模块提供了一些有用的集合类,可以根据需要选用。
计数 Counter
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"
counter的参数形式
from collections import Counter
c = Counter() # a new, empty counter
c = Counter('gallahad') # a new counter from an iterable
c = Counter({'red': 4, 'blue': 2}) # a new counter from a mapping
c = Counter(cats=4, dogs=8) # a new counter from keyword args
#### 没有的元素会返回0
c = Counter(['eggs', 'ham'])
c['bacon']
0
## 删除元素需要用del
c['sausage'] = 0 # counter entry with a zero count
print(c)
del c['sausage'] # del actually removes the entry
print(c)
Counter({'eggs': 1, 'ham': 1, 'sausage': 0})
Counter({'eggs': 1, 'ham': 1})
c = Counter(['eggs', 'ham'])
## 返回元素的迭代器,每个元素value是多少就出现多少次,element的顺序是任意的,value 小于1的元素不会被返回.
c.elements(),list(c.elements())
## 返回value最大的前n个
c.most_common(1)
## .subtract(iterable or mapping),元素相减,未出现的元素会被添加
c.subtract(['eggs','eggs'])
print(c)
c.subtract({'eggs':-2,'ham':3})
print(c)
c.subtract(['milk'])
print(c)
## .update()[iterable-or-mapping],元素相加,未出现的会被添加
c.update(['milk'])
print(c)
(<itertools.chain at 0x26dc0f4f088>, ['eggs', 'ham'])
[('eggs', 1)]
Counter({'ham': 1, 'eggs': -1})
Counter({'eggs': 1, 'ham': -2})
Counter({'eggs': 1, 'milk': -1, 'ham': -2})
Counter({'eggs': 1, 'milk': 0, 'ham': -2})
常用命令
c = Counter(['eggs', 'ham'])
sum(c.values()) # total of all counts
c.clear() # reset all counts
c = Counter(['eggs', 'ham'])
list(c) # list unique elements
set(c) # convert to a set
dict(c) # convert to a regular dictionary
c.items() # convert to a list of (elem, cnt) pairs
##Counter(dict(list_of_pairs)) # convert from a list of (elem, cnt) pairs
c.most_common()[:-2-1:-1] # n least common elements
+c # remove zero and negative counts
2
['eggs', 'ham']
{'eggs', 'ham'}
{'eggs': 1, 'ham': 1}
dict_items([('eggs', 1), ('ham', 1)])
[('ham', 1), ('eggs', 1)]
Counter({'eggs': 1, 'ham': 1})
shutil
方法 | 功能说明 |
---|---|
copy(src, dst) | 复制文件,新文件具有同样的文件属性,如果目标文件已存在则抛出异常 |
copy2(src, dst) | 复制文件,新文件具有原文件完全一样的属性,包括创建时间、修改时间和最后访问时间等等,如果目标文件已存在则抛出异常 |
copyfile(src, dst) | 复制文件,不复制文件属性,如果目标文件已存在则直接覆盖 |
copyfileobj(fsrc, fdst) | 在两个文件对象之间复制数据,例如copyfileobj(open(‘123.txt’), open(‘456.txt’, ‘a’)) |
copymode(src, dst) | 把src的模式位(mode bit)复制到dst上,之后二者具有相同的模式 |
copystat(src, dst) | 把src的模式位、访问时间等所有状态都复制到dst上 |
copytree(src, dst) | 递归复制文件夹 |
disk_usage(path) | 查看磁盘使用情况 |
move(src, dst) | 移动文件或递归移动文件夹,也可以给文件和文件夹重命名 |
rmtree(path) | 递归删除文件夹 |
make_archive(base_name, format, root_dir=None, base_dir=None) | 创建tar或zip格式的压缩文件 |
unpack_archive(filename, extract_dir=None, format=None) | 解压缩压缩文件 |
itertools
These tools and their built-in counterparts also work well with the high-speed
functions in the operator
module. For example, the multiplication
operator can be mapped across two vectors to form an efficient dot-product:
sum(map(operator.mul, vector1, vector2))
.
Iterator |
Arguments |
Results |
Example |
---|---|---|---|
start, [step] |
start, start+step, start+2*step, … |
|
|
p |
p0, p1, … plast, p0, p1, … |
|
|
elem [,n] |
elem, elem, elem, … endlessly or up to n times |
|
import itertools
itertools.count(10)
for i in itertools.count(10):
print(i)
if i>11:
break
count(10)
10
11
12
itertools.cycle('abcd')#itetable
a=0
for i in itertools.cycle('abcd'):
print(i)
a+=1
if a>1:
break
<itertools.cycle at 0x26dc0e34098>
a
b
itertools.repeat('b')#无限的迭代器
itertools.repeat('b',5)
repeat('b')
repeat('b', 5)
Iterators terminating on the shortest input sequence
Iterator |
Arguments |
Results |
Example |
---|---|---|---|
p [,func] |
p0, p0+p1, p0+p1+p2, … |
|
|
p, q, … |
p0, p1, … plast, q0, q1, … |
|
|
iterable |
p0, p1, … plast, q0, q1, … |
|
|
data, selectors |
(d[0] if s[0]), (d[1] if s[1]), … |
|
|
pred, seq |
seq[n], seq[n+1], starting when pred fails |
|
|
pred, seq |
elements of seq where pred(elem) is false |
|
|
iterable[, key] |
sub-iterators grouped by value of key(v) |
||
seq, [start,] stop [, step] |
elements from seq[start:stop:step] |
|
|
func, seq |
func(*seq[0]), func(*seq[1]), … |
|
|
pred, seq |
seq[0], seq[1], until pred fails |
|
|
it, n |
it1, it2, … itn splits one iterator into n |
||
p, q, … |
(p[0], q[0]), (p[1], q[1]), … |
|
累加.accumulate()
list(itertools.accumulate(range(5)))
[0, 1, 3, 6, 10]
链式遍历多个迭代器 .chain()
list(itertools.chain(range(5),'abcd'))
[0, 1, 2, 3, 4, 'a', 'b', 'c', 'd']
链式遍历迭代器中的每个元素 .chain.from_iterable()
list(itertools.chain.from_iterable(['abcd','efgh']))
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
根据一个序列的True/False选择另一个序列 .compress()
list(itertools.compress('abcd',[1,0,0,1]))
['a', 'd']
根据施加于每个元素的条件决定从哪个元素开始迭代 .dropwhile()
从条件不满足的元素开始
list(itertools.dropwhile(lambda x:x>5,range(10)))#第一个元素就失败了
list(itertools.dropwhile(lambda x:x<5,range(10)))
[5, 6, 7, 8, 9]
获取不满足的元素形成的迭代器 .filterfalse()
list(itertools.filterfalse(lambda x:x%2,range(10)))
[0, 2, 4, 6, 8]
.grouby()
groupby()把迭代器中相邻的重复元素挑出来放在一起
实际上挑选规则是通过函数完成的,只要作用于函数的两个元素返回的值相等,这两个元素就被认为是在一组的,而函数返回值作为组的key。如果我们要忽略大小写分组,就可以让元素’A’和’a’都返回相同的key
for key, group in itertools.groupby('AAABBBCCAAA'):
print(key, list(group))
for key, group in itertools.groupby('AaaBBbcCAAa', lambda c: c.upper()):
print(key, list(group))
A ['A', 'A', 'A']
B ['B', 'B', 'B']
C ['C', 'C']
A ['A', 'A', 'A']
A ['A', 'a', 'a']
B ['B', 'B', 'b']
C ['c', 'C']
A ['A', 'A', 'a']
.islice() 切片
list(itertools.islice(range(10),3,8,2))
[3, 5, 7]
.starmap() 映射,seq的元素也必须是迭代器
list(itertools.starmap(max,[[1,2,3],[4,5,6],[7,8,9]]))
[3, 6, 9]
.takewhile(pred,iterable) 获取直到条件不满足之前的元素
list(itertools.takewhile(lambda x:x<5,range(10)))
[0, 1, 2, 3, 4]
.tee(iterable,n) 返回n个独立的相同的迭代器
list(map(list,itertools.tee(list(range(10)),5)))
[[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]]
.ziplongest()
##zip是取最短的,这个取最长的,并且可以设置填补值
list(itertools.zip_longest('abcd','123','xyz',fillvalue='-'))
[('a', '1', 'x'), ('b', '2', 'y'), ('c', '3', 'z'), ('d', '-', '-')]
Combinatoric iterators
Iterator |
Arguments |
Results |
---|---|---|
p, q, … [repeat=1] |
cartesian product, equivalent to a nested for-loop |
|
p[, r] |
r-length tuples, all possible orderings, no repeated elements |
|
p, r |
r-length tuples, in sorted order, no repeated elements |
|
p, r |
r-length tuples, in sorted order, with repeated elements |
|
|
|
|
|
|
|
|
|
|
|
|
product(seq,repeat=n) 有序排列$A_{n_{seq}}^n$,元素可重复
list(itertools.product('ABCD',repeat=2))
[('A', 'A'),
('A', 'B'),
('A', 'C'),
('A', 'D'),
('B', 'A'),
('B', 'B'),
('B', 'C'),
('B', 'D'),
('C', 'A'),
('C', 'B'),
('C', 'C'),
('C', 'D'),
('D', 'A'),
('D', 'B'),
('D', 'C'),
('D', 'D')]
.permutations(seq,n) 有序排列,元素不可重复
list(itertools.permutations('ABCD',2))
[('A', 'B'),
('A', 'C'),
('A', 'D'),
('B', 'A'),
('B', 'C'),
('B', 'D'),
('C', 'A'),
('C', 'B'),
('C', 'D'),
('D', 'A'),
('D', 'B'),
('D', 'C')]
.combinations(seq,n) 无序组合,元素不可重复
list(itertools.combinations('ABCD',2))
[('A', 'B'), ('A', 'C'), ('A', 'D'), ('B', 'C'), ('B', 'D'), ('C', 'D')]
.combinations_with_replacement(seq,2) 无序组合,元素可重复
list(itertools.combinations_with_replacement('ABCD',2))
[('A', 'A'),
('A', 'B'),
('A', 'C'),
('A', 'D'),
('B', 'B'),
('B', 'C'),
('B', 'D'),
('C', 'C'),
('C', 'D'),
('D', 'D')]
functools
import functools
partial 偏函数
-
partial(func, *args, **keywords)
用于创建一个偏函数,将默认参数包装一个可调用对象,返回结果也是可调用对象。 偏函数可以固定住原函数的部分参数,从而在调用时更简单。
int8=functools.partial(int,base=8)
int8('123')
83
.reduce 对每两个元素累积进行函数运算
functools.reduce(lambda x,y:x+y,[1,2,3])
6