Guide
file example
读取文件处理传统写法,需要确保文件正常打开之后,即使出现异常,也能够正常关闭。写法不够优雅。
1 | try: |
with语句时用于对try except finally 的优化,让代码更加美观。同时确保即使执行异常,finally中的语句也可以执行。
with-as 重写
1 | with open("./1.txt") as file: |
with-as 原理
基本思想是with所求值的对象必须有一个__enter__()
方法,一个__exit__()
方法。
原理:
- with后面的语句被求值后返回对象A;
- 调用对象A的
__enter__()
方法将返回值赋给as后面的变量B; - 执行with后面的代码块;
- 当with后面的代码块全部被执行完之后(或者由于抛出异常没有正常习执行完毕),最终都会调用A对象的
__exit__()
方法进行清理工作。
1 | class Sample: |
output
In __enter__()
sample: Foo
In __exit__()
steps:
- 执行with后面的语句get_sample()返回对象sample
- 执行sample对象的
__enter__()
方法,返回string类型的”Foo”赋值给as后面的s变量 - 执行代码块,打印变量”sample”的值为 “Foo”
- 代码块执行完毕,调用sample对象的
__exit__()
方法进行清理工作
with 处理异常
with除了可以进行清理工作之外,真正强大之处是可以处理异常。Sample类的__exit__
方法有三个参数:val
, type
和 trace
。 这些参数在异常处理中相当有用。
1 | class Sample: |
output
type: <type 'exceptions.ZeroDivisionError'>
value: integer division or modulo by zero
trace: <traceback object at 0x0000000004A5AA08>
ZeroDivisionErrorTraceback (most recent call last)
<ipython-input-9-282d3906c5ac> in <module>()
13
14 with Sample() as sample:
---> 15 sample.do_something()
<ipython-input-9-282d3906c5ac> in do_something(self)
9
10 def do_something(self):
---> 11 bar = 1/0
12 return bar + 10
13
ZeroDivisionError: integer division or modulo by zero
在执行代码块sample.do_something()
的时候由于异常抛出,与之关联的type,value和stack trace传给__exit__()
方法,因此抛出的ZeroDivisionError
异常被打印出来了。
file 对象
python中的file对象已经实现了__enter__()
和__exit__()
方法
1 | file = open("./1.txt") |
1 | file.__enter__() |
<open file './1.txt', mode 'r' at 0x00000000049FF030>
1 | file.read(1) |
1 | file.__exit__() |
1 | file.read(1) |
ValueErrorTraceback (most recent call last)
<ipython-input-19-d0e1662399bb> in <module>()
----> 1 file.read(1)
ValueError: I/O operation on closed file
Reference
History
- 20181023: created.