4.10 with正确使用
任何一门编程语言中,文件的输入输出、数据库的连接断开等,都是很常见的资源管理操作。但资源是有限的,在编写代码时,必须保证这些资源在使用后得到释放,不然容易造成资源泄漏,轻者使得系统处理缓慢,严重时会使系统崩溃。
为了更好地避免此类问题,不同的编程语言引入了不同的机制。在Python中,对应的解决方式是使用with as语句操作上下文管理器,上下文管理器能够帮助我们自动分配并且释放资源。有一些任务可能事先需要设置,事后做清理工作。对于这种场景,Python的with as语句提供了一种非常方便的处理方式。例如,使用with as语句操作已经打开的文件对象,无论程序运行期间是否抛出异常,都保证with as语句执行完毕后自动关闭已经打开的文件。
除了有更优雅的语法,with as语句还可以很好地处理上下文环境产生的异常。with as语句通过__enter__()方法初始化,然后在__exit__()中做善后和异常处理,所以使用with处理的对象必须有__enter__()和__exit__()这两个方法。
with as语句的语法格式如下:
with expression [as target]:
with_body
参数说明如下:
expression是一个需要执行的表达式;
target是一个变量或元组,存储的是expression表达式执行后返回的结果,[]表示该参数为可选参数。
with as语句的执行流程如下。
(1)运行expression表达式,如果表达式含有计算、类初始化等内容,将优先执行。
(2)运行内置的__enter__()方法中的代码。
(3)运行with_body中的代码。
(4)运行__exit__()方法中的代码进行善后,如释放资源、处理错误等。
示例如下:
#!/usr/bin/env python
class Sample:
def __enter__(self):
return self
def __exit__(self, type, value, trace):
print "type:", type
print "value:", value
print "trace:", trace
def do_something(self):
bar = 1/0
return bar + 10
with Sample() as sample:
sample.do_something()
在示例中,只要紧跟with后面的语句所返回的对象有__enter__()和__exit__()方法即可实现上下文资源的管理。此例中,Sample()的__enter__()方法返回新创建的Sample对象,并赋值给变量sample。代码执行后输出如下:
type: <type 'exceptions.ZeroDivisionError'>
value: integer division or modulo by zero
trace: <traceback object at 0x1004a8128>
Traceback (most recent call last):
File "./with_example02.py", line 19, in <module>
sample.do_something()
File "./with_example02.py", line 15, in do_something
bar = 1/0
ZeroDivisionError: integer division or modulo by zero
实际上,在with的代码块抛出异常时,__exit__()方法将被执行。正如示例中,异常抛出时,与之关联的type、value和stack trace传入__exit__()方法,因此抛出的ZeroDivisionError异常被输出。在开发模块时,清理资源、关闭文件等操作都可以放在__exit__()方法当中。
因此,Python的with as语句提供了一个有效的让代码更简练的机制,同时让异常产生时的清理工作更简单。
此外,with as语句支持嵌套多环境管理器,语法如下:
with A() as a, B() as b:
...statements...
它等价于嵌套的with as语句:
with A() as a:
with B() as b:
...statements...
多环境管理器管理的多个对象会在with as语句的代码块出现异常时,或者执行完with as语句的代码块时全部自动被清理。
例如,打开两个文件,将它们的内容通过zip()合并在一起,然后同时关闭它们:
with open('a.file') as f1, open('b.file') as f2:
for pair in zip(f1, f2):
print(pair)
总结一下,with语句适用于需要访问资源的场景,确保不管使用过程中是否发生异常都会执行必要的“清理”操作,以释放资源,例如文件使用后自动关闭、线程中锁的自动获取和释放等。
版权声明:51Testing软件测试网获得作者授权连载本书部分章节。
任何个人或单位未获得明确的书面许可,不得对本文内容复制、转载或进行镜像,否则将追究法律责