上下文管理器
说明:
上下文管理器和迭代器很相似,实现了迭代协议函数的对象即为迭代器,实现了上下文协议函数对象即为上下文管理器。迭代器实现了__iter__和__next__方法。而上下文管理器则是__enter__和__exit__方法。
class Contexto(object):
def __enter__(self):
pass
def __exit__(self, exc_type, exc_val, exc_tb):
pass
contexto=Contexto()
说明:
Contexto实现了__enter__和__exit__上下管理器协议,当实例化对象的时候则创建了上下文管理器contexto。
class Contexto(object):
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
pass
contexto=Contexto()
with contexto as var :
print(var)
说明:
配合with语句的时候,上下文管理器会自动调用__enter__,然后进入上下文运行时环境,如果有as语句,返回自身或另一个与运行时上下文相关的对象,值赋值给var。当后面的语句执行完毕,或者发生异常,就会进入__exit__方法内,并且会把对于异常的参数传过来,如果__exit__方法返回的是True,则with语句块不会显示抛出异常,终止程序,如果返回None或者False,异常会被主动raise,并终止程序。
为什么要用上下文管理器?
- 可以以一种更加优雅的方式,操作(创建/获取/释放)资源,如文件操作、数据库连接;
- 可以以一种更加优雅的方式,处理异常;
说明:
处理异常,通常都是使用 try...execept..
来捕获处理的。这样做一个不好的地方是,在代码的主逻辑里,会有大量的异常处理代理,这会很大的影响我们的可读性。
class Contexto(object):
def __enter__(self):
print()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
return True
def opens(self):
a=1+''
print(a)
contexto=Contexto()
with contexto as var :
var.opens()
说明:
异常可以在__exit__
进行捕获并由你自己决定如何处理,是抛出呢还是在这里就解决了。在__exit__
里返回 True
(没有return 就默认为 return False),就相当于告诉 Python解释器,这个异常我们已经捕获了,不需要再往外抛了。
在 写__exit__
函数时,需要注意的事,它必须要有这三个参数:
- exc_type:异常类型
- exc_val:异常值
- exc_tb:异常回溯追踪
当主逻辑代码没有报异常时,这三个参数将都为None。
上下管理器工具
import contextlib
@contextlib.contextmanager
def contexts(file_name):
print('首先进入我__enter__')
file_one=open(file_name,'r')
yield file_one #yield 之前为__enter__ yield 之后为__exit__
print('然后进入我__exit__')
file_one.close()
with contexts('yu.txt') as f:
for i in f:
print(i)
说明:
这段代码并不能实现异常处理,需要处理异常还是需要try...excetp...finally
import contextlib
@contextlib.contextmanager
def contexts(file_name):
print('首先进入我__enter__')
file_one=open(file_name,'r')
try:
yield file_one
except (ValueError,Exception) as f :
print(f)
finally:
file_one.close()
return
with contexts('yu.txt') as f:
for i in f:
i/0 #错误
print(i) #首先进入我__enter__
unsupported operand type(s) for /: 'str' and 'int'
总结:上下文管理工具重点在于yield ,在之前为__enter__,之后如为__exit__。在管理工具中管理资源可以这样,但是在处理异常的时候还是需要try...excetp...finally语句来实现。