一:with语句的作用
with语句是用来调用上下文管理器的,没有上下文管理器就没有with。
二:什么是上下文管理器
上下文管理器是一种对象,这种对象包含了两个方法:__enter__()和__exit__(),当调用上下文管理器时会执行__enter__()方法并把__enter__()的返回值赋给as子句的变量(如果有的话),而with语句体执行结束后或出错时会调用__exit__()方法。
三:with语句的语法格式以及原理
with 语句的语法格式如下:
1
2
|
with context_expression [as target(s)]:
with-body
|
这里 context_expression 要返回一个上下文管理器对象,该对象并不赋值给 as 子句中的 target(s) ,如果指定了 as 子句的话,会将上下文管理器的 __enter__() 方法的返回值赋值给 target(s)。target(s) 可以是单个变量,或者由“()”括起来的元组(不能是仅仅由“,”分隔的变量列表,必须加“()”)。
四:实现一个上下文管理器
要实现一个上下文管理器,就是要实现__enter__()和__exit__()这两个方法,这两个方法的定义如下:
- context_manager.__enter__() :进入上下文管理器的运行时上下文,在语句体执行前调用。with 语句将该方法的返回值赋值给 as 子句中的 target,如果指定了 as 子句的话
- context_manager.__exit__(exc_type, exc_value, exc_traceback) :退出与上下文管理器相关的运行时上下文,返回一个布尔值表示是否对发生的异常进行处理。参数表示引起退出操作的异常,如果退出时没有发生异常,则3个参数都为None。如果发生异常,返回
(1)实现一个最简单的上下文管理器:
class test_with: def __enter__(self): print('in entry') def __exit__(self, *args): print('in exit') with test_with(): print('in with statment')
在这个上下文管理器中实现了两个方法,没有使用as子句,__exit__()方法没有接受参数,没有实现__init__()方法。运行结果:create one test_with object in entry in with statment in exit
(2)向上下文管理器中添加内容,实现一个简单的除法。
执行了两次,第二次执行时在with语句体中抛出一个错误class div: def __init__(self, num1, num2): self.num1 = num1 self.num2 = num2 self.res = num1 / num2 class test_with: def __init__(self, num1, num2): self.str = 'one test_with object' print('in init, create {}'.format(self.str)) self.num1 = num1 self.num2 = num2 def __enter__(self): print('in entry') if self.num2 == 0: raise Exception div_obj = div(self.num1, self.num2) return div_obj def __exit__(self, exc_type, exc_value, exc_traceback): print('in exit') if exc_tracebackb is not None: print('Error!') return False else: print('Success!') with test_with(2, 1) as div_obj: print('in with statment') print('{} / {} = {}'.format( div_obj.num1, div_obj.num2, div_obj.res)) with test_with(2, 1) as div_obj: print('in with statment') raise Exception print('{} / {} = {}'.format( div_obj.num1, div_obj.num2, div_obj.res))
运行结果:
两次执行后都会调用__exit__()方法。说明发生异常之后正确的进行了处理。in init, create one test_with object in entry in with statment 2 / 1 = 2 in exit Success! in init, create one test_with object in entry in with statment in exit Error! Traceback (most recent call last): File "test_with.py", line 39, in <module> raise Exception Exception
五:__exit__()方法的参数与返回值
(1)参数
参数表示引起退出操作的异常,如果退出时没有发生异常,则3个参数都为None。type时异常的类型,value是异常的值,traceback是异常的位置。
(2)返回值
__exit__()方法可以有返回值,表示是否对异常进行另外处理(或表示__exit__方法是否已经处理异常),若无返回值,则会默认为False,会在退出该方法后重新抛出异常由with之外的语句进行异常处理。若返回值为True,则不会对异常进行处理,不会出现上面执行时的Traceback的报错信息。
参考文章:https://www.ibm.com/developerworks/cn/opensource/os-cn-pythonwith/