一、errno
在日常开发中经常需要捕获各种异常,做特殊处理。举个例子:
os.kill(12345,0)
输出
Traceback (most recent call last):
File "/Users/zhangkun/Documents/GitHub/geektime/test.py", line 4, in <module>
os.kill(12345,0)
ProcessLookupError: [Errno 3] No such process
信号为0,表示这只是检查PID的有效性。根据提示,这是一个“Nosuchprocess”类型的错误,注意方括号中的“Errno3”,这其实是Python内置的错误系统提供的编号:
In:os.strerror(3)
Out:'Nosuchprocess'
还可以使用errno模块找到对应的错误类型,更精准地做异常处理(errno_example.py):
import os
import errno
def listdir(dirname):
try:
os.listdir(dirname)
except OSError as e:
error = e.errno
if error == errno.ENOENT:
print('no such file or directory')
elif error == errno.EACCES:
print('Permission denied')
elif error == errno.ENOSPC:
print('No space left on device')
else:
print(e.strerror)
for filename in ['/no/such/dir', '/root', '/home/ubuntu']:
listdir(filename)
通过对比异常对象的errno属性值就能知道异常类型。
二、subprocess
subprocess模块用来取代如下模块和函数:
os.system
os.spawn*
os.popen*
popen2.*
commands.*
1.call:执行系统命令,可以替代os.system。call只返回命令的返回值。
In:subprocess.call('ls-l/tmp/mongodb27017.sock',shell=True)
srwx------1 mongodbmongodb0May1012:24/tmp/mongodb27017.sock
Out:0
In:subprocess.call('exit1',shell=True)
Out:1
通常由于安全问题,不建议使用shell=True,可以把命令拆分成列表
In:subprocess.call(['ls','/tmp/mongodb27017.sock'],shell=False)
/tmp/mongodb27017.sock
Out:0
拆分命令最简单的方法是使用shlex模块:
In:shlex.split('ls/tmp/mongodb27017.sock')
Out:['ls','/tmp/mongodb27017.sock']
2.check_call:添加了错误处理的执行系统命令方法。当执行call方法的返回值不为0,就会抛出CalledProcessError异常。
3.Popen:一个用来执行子进程的类,通过communicate方法获得执行结果:
4. 4.check_output:在Python2.7和Python3中都可用,它比Popen更简单地获得输出,但是需要执行的返回值为0,否则仍然抛出CalledProcessError异常。
在出现错误的时候,可以额外地执行exit0,就能正常获得输出:
三、contextlib
写Python代码的时候经常将一系列操作放在一个语句块中,Python2.5加入了with语法,实现上下文管理功能,这让代码的可读性更强并且错误更少。最常见的例子就是open,如果不使用with,使用open时会是这样
import threading
lock = threading.Lock()
lock.acquire()
my_list = []
item = 1
try:
my_list.append(item)
finally:
lock.release()
如果使用with就会非常简单
with lock:
my_list.append(item)
创建上下文管理器实际就是创建一个类,添加__enter__和__exit__方法。看看threading.Lock的上下文管理功能是怎么实现的:
import threading
class LockContext(object):
def __init__(self):
print('__init__')
self.lock=threading.Lock()
def __enter__(self):
print('__enter__')
self.lock.acquire()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print('__exit__')
self.lock.release()
with LockContext():
print('in the context')
输出:
__init__
__enter__
in the context
__exit__
上面的例子比较简单,在执行self.__enter__的时候没有传递参数。下面我们来实现open的上下文管理功能:
自定义上下文管理器确实很方便,但是Python标准库还提供了更易用的上下文管理器工具模块contextlib,它是通过生成器实现的,我们不必再创建类以及__enter__和__exit__这两个特殊的方法:
from contextlib import contextmanager
@contextmanager
def make_open_context(filename,mode):
fp = open(filename,mode)
try:
yield fp
finally:
fp.close()
with make_open_context('/tmp/a','a') as f:
f.write('hello world')
yield关键词把上下文分割成两部分:yield之前就是__init__中的代码块;yield之后其实就是__exit__中的代码块;yield生成的值会绑定到with语句as子句中的变量(如果没有生成,也就没有as字句)。
四、glob
glob用来匹配UNIX风格的路径名字的模块,它支持“”、“?”、“[]”这三种通配符,“”代表0个或多个字符,“?”代表一个字符,“[]”匹配指定范围内的字符,例如[09]匹配数字。我们先创建一个目录,目录中包含如下文件:
五、operator
operator是一个内建操作的函数式接口。举个例子,如果想对列表的值求和,可以使用sum,但是如果要相乘呢?其实可以结合reduce和operator模块来实现:
operator模块还提供了非常有用的itemgetter、attrgetter和methodcaller方法。
- itemgetter。通过被求值对象的__getitem__方法获得符合的条目:
另一个使用itemgetter的场景是排序:
2.attrgetter。attrgetter根据被求值对象的属性获得符合条件的结果:
再简单一点:
reduce(getattr,'b,c,d'.split('.'),a)
而使用attrgetter就很简洁:
operator.attrgetter('b.c.d')(a)
3.methodcaller。methodcaller将调用被求值对象的方法:
六、functools
functools模块中包含了一系列操作其他函数的工具。
1.partial。partial可以重新定义函数签名,也就是在执行函数之前把一些参数预先传给函数,待执行时传入的参数数量会减少。
2.wraps。把被封装函数的__name__、module、__doc__和__dict__复制到封装函数中,这样在未来排错或者函数自省的时候能够获得正确的源函数的对应属性,所以使用wraps是一个好习惯。我们先看不使用wraps的例子:
3.total_ordering。对比自定义对象需要添加__lt__、le、gt、ge__和__eq__等方法,如果使用total_ordering,只需要定义__eq,以及定义__lt__、le、gt、__ge__四种方法之一就可以了:
4.cmp_to_key。Python2的sorted函数除了通过指定key参数的值作为依据来排序,还支持cmp参数:
除了兼容Python3的sorted,还可以把比较函数转换后用于min、max、heapq.nlargest、heapq.nsmallest、itertools.groupby等支持key参数的函数上。
七、collections
collections包含5个高性能的计算器工具
1. Counter 一个方便、快速计算的计时器工具
可以直接list()将Counter类型对象转为列表
2.deque:一个双端队列,能够在队列两端添加或删除队列元素。它支持线程安全,能够有效利用内存。无论从队列的哪端入队和出队,性能都能够接近于O(1)。
3.defaultdict。defaultdict简化了处理不存在的键的场景。如果不使用defaultdict,对一个单词的计数要这样实现:
defaultdict参数就是值的类型,还可以使用自定义类型。下面演示一个插入后自动排序的自定义列表类型:
4.OrderedDict。Python的dict结构是无序的:
5.namedtuple。namedtuple能创建可以通过属性访问元素内容的扩展元组。使用namedtuple能创建更健壮、可读性更好的代码。
假设不使用namedtuple,查询数据库获得如下一条记录: