Python with as语句的正确用法
任何一门编程语言中,文件的输入输出、数据库的连接断开等,都是很常见的资源管理操作。但资源是有限的,在编写代码时,必须保证这些资源在使用后得到释放,不然容易造成资源泄漏,轻者使得系统处理缓慢,严重时会使系统崩溃。
为了更好地避免此类问题,不同的编程语言引入了不同的机制。在 Python 中,对应的解决方式是使用 with as 语句操作上下文管理器,上下文管理器能够帮助我们自动分配并且释放资源。
有一些任务可能事先需要设置,事后做清理工作。对于这种场景,Python 的 with as 语句提供了一种非常方便的处理方式。例如,使用 with as 语句操作已经打开的文件对象,无论程序运行期间是否抛出异常,都保证 with as 语句执行完毕后自动关闭已经打开的文件。
除了有更优雅的语法,with as 语句还可以很好地处理上下文环境产生的异常。
with as 语句通过 __enter__() 方法初始化,然后在 __exit__() 中做善后和异常处理,所以使用 with 处理的对象必须有 __enter__() 和 __exit__() 这两个方法。
Python 中 with as 语句的语法格式如下:
with as 语句的执行流程如下:
示例如下:
代码执行后输出如下:
因此,Python 的 with as 语句提供了一个有效的让代码更简练的机制,同时让异常产生时的清理工作更简单。
此外,with as 语句支持嵌套多环境管理器,语法如下:
例如,打开两个文件,将它们的内容通过 zip() 合并在一起,然后同时关闭它们:
为了更好地避免此类问题,不同的编程语言引入了不同的机制。在 Python 中,对应的解决方式是使用 with as 语句操作上下文管理器,上下文管理器能够帮助我们自动分配并且释放资源。
有一些任务可能事先需要设置,事后做清理工作。对于这种场景,Python 的 with as 语句提供了一种非常方便的处理方式。例如,使用 with as 语句操作已经打开的文件对象,无论程序运行期间是否抛出异常,都保证 with as 语句执行完毕后自动关闭已经打开的文件。
除了有更优雅的语法,with as 语句还可以很好地处理上下文环境产生的异常。
with as 语句通过 __enter__() 方法初始化,然后在 __exit__() 中做善后和异常处理,所以使用 with 处理的对象必须有 __enter__() 和 __exit__() 这两个方法。
Python 中 with as 语句的语法格式如下:
with expression [as target]: with_body参数说明如下:
- expression 是一个需要执行的表达式;
- target 是一个变量或元组,存储的是 expression 表达式执行后返回的结果,[] 表示该参数为可选参数。
with as 语句的执行流程如下:
- 运行 expression 表达式,如果表达式含有计算、类初始化等内容,将优先执行。
- 运行内置的 __enter__() 方法中的代码。
- 运行 with_body 中的代码。
- 运行 __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)