应用场景
有一些任务,事前需要设置,事后需要清理。 对于这类任务,python提供了一套很方便的机制帮助用户完成事前事后的处理(嗯,就是替用户擦屁股),方便用户专注于自己的代码,同时也提高了代码的健壮性(毕竟只有用户用得爽,才会有回头客)。
举个例子,python中读取文件,通常需要三步:
> file = open("...")
> file.read()
> ... # do something
> file.close()
但这样赤果果的调用,很容易出问题,open到close之间任何一步出现问题,一场退出,都会导致close操作执行不了,从而导致内存泄漏。为了让代码更加健壮,需要加上异常处理,常见的异常处理就是try…finally.
>try:
> file = open("...")
> file.read()
> ... # do something
> finally:
> file.close()
从功能上来说,try…finally已经可以cover住了,但是就是用户 懒 了,不愿整这一套,于是python就提供了with机制
前生 – try…finally
如上分析,哈哈。
语法
标准版:
with expression as obj:
body
形象版:
class Sample:
def __enter__(self):
...
return self
def __exit(self, type, value, trace):
...
def do_something():
...
with Sample() as sam:
sam.do_something()
语法解释:
- expression 用于返回一个对象,这个对象含有enter()和exit()方法。
- obj 是enter()方法的返回值
- body用于用户实现内容
- exit()函数默认有四个参数,后三个参数只有在body执行异常才会有值,分别表示异常类型,异常值,代码追踪。
工作流程:
- step1: 调用expression, 获取一个对象
- step2:调用对象的enter()函数,并将enter()函数的返回值返回给obj
- step3:执行body块语句,
- step4:执行对象的exit()函数完成清理工作,如果body块执行异常,也可以会在exit()函数中打印出来
case
class Cls:
def __exit__(self, type, value, trace):
print("__exit__")
print("type: ", type)
print("value: ", value)
print("trace: ", trace)
def __enter__(self):
print("__enter__")
return self
def exit(self, *kargs, **kwargs):
print("__exit")
def enter(self):
print("__enter")
def do_something(self):
assert 1>2
print("do something")
def get_class():
my_cls = Cls()
return my_cls
with get_class() as cls:
get_class().do_something()
cls.do_something()
执行结果:
__enter__
__exit__
('type: ', <type 'exceptions.AssertionError'>)
('value: ', AssertionError())
('trace: ', <traceback object at 0x1054816c8>)
Traceback (most recent call last):
File "with.py", line 24, in <module>
get_class().do_something()
File "with.py", line 15, in do_something
assert 1>2
AssertionError