军事信息化建设网站,o2o网站建设行情,怎么用一个主机做多个网站,全国网站制作公司目录with语句上下文管理器原理自定义上下文管理器contextmanager 装饰器with语句
在我们日常使用场景中#xff0c;经常会操作一些资源#xff0c;比如文件对象、数据库连接、Socket连接等#xff0c;资源操作完了之后#xff0c;不管操作的成功与否#xff0c;最重要的事…
目录with语句上下文管理器原理自定义上下文管理器contextmanager 装饰器with语句
在我们日常使用场景中经常会操作一些资源比如文件对象、数据库连接、Socket连接等资源操作完了之后不管操作的成功与否最重要的事情就是关闭该资源否则资源打开太多而没有关闭程序会报错以文件操作为例通常我们会这样写
f open(file.txt, w)
try:f.write(Hello)
finally:f.close()但既然close方法是必须的操作那就没必要显式地调用所以Python给我们提供了一种更优雅的方式使用with语句
with open(file.txt, w) as f:f.write(Hello)在退出with语句下的代码块之后f 对象会自动执行自己的close方法实现资源的释放简洁优雅。
上下文管理器原理
上下文管理器实际是内部实现了__enter__和__exit__方法的对象。
当我们使用with语法时
__enter__()方法返回一个值可以将它赋值给as后面的对象例如上面的中的f
__exit__()方法with语句退出或者发送异常时会执行这个方法。
1、__enter__方法说明
上下文管理器的__enter__方法是可以带返回值的默认返回None这个返回值通过with…as…中的 as 赋给它后面的那个变量所以 with EXPR as VAR 就是将EXPR对象__enter__方法的返回值赋给 VAR。
当然with...as...并非固定组合单独使用with...也是可以的上下文管理器的__enter__方法还是正常执行只是这个返回值并没有赋给一个变量with下面的代码块也不能使用这个返回值。
2、__exit__方法说明
上下文管理器的__exit__方法接收3个参数exc_type、exc_val、exc_tb如果代码块BLOCK发生了异常e并退出这3个参数分别为type(e)、str(e)、e.__traceback__否则都为None。
同样__exit__方法也是可以带返回值的这个返回值应该是一个布尔类型True或False默认为None即False。如果为False异常会被抛出用户需要进行异常处理。如果为True则表示忽略该异常。
一个上下文管理器一般使用如下
with EXPR as VAR:BLOCK上述代码的执行过程等价于
ContextManager EXPR
VAR ContextManager.__enter__()
try:BLOCK
finally:ContextManager.__exit__()f 对象就是把自己的close方法定义在了它的__exit__方法内部实现了代码块BLOCK执行完之后自动关闭自身。
自定义上下文管理器
下面我们定义一个文件类内部实现了__enter__和__exit__两个方法
class File:def __init__(self, filename, mode):self.filename filenameself.mode modedef __enter__(self):print(进入)self.f open(self.filename, self.mode)return self.fdef __exit__(self, exc_typeNone, exc_valNone, exc_tbsNone):print(退出)self.f.close()这时候File类就是一个上下文管理器
我们分别通过 with语句 和 try/finally语句 使用File类对文件进行写入操作
通过with语句执行
with File(file.txt, w) as f:print(正在写入...)f.write(Hello)控制台输出
进入
正在写入...
退出并得到了一个写了 Hello 的 file.txt 文件
通过try/finally语句执行
ContextManager File(file.txt, w)
VAR ContextManager .__enter__()
try:print(正在写入...)VAR.write(Hello)
finally:ContextManager.__exit__()控制台输出
进入
正在写入...
退出并得到了一个写了 Hello 的 file.txt 文件
两者输出一致所以验证了二中执行过程的等价关系是正确的。
contextmanager 装饰器
Python还提供了一个contextmanager装饰器允许用户将一个生成器定义为上下文管理器该装饰器将生成器中的代码通过yield语句分成两部分yield之前的代码为__enter__方法yield之后的代码为__exit__方法yield的返回值即__enter__方法的返回值用于赋给as后的变量。
下面我们通过contextmanager装饰器也实现一个关于文件的上下文管理器
from contextlib import contextmanagercontextmanager
def open_file(filename, mode):print(进入)f open(filename, mode)try:yield ffinally:print(退出)f.close()说明这里使用 try/finally 是确保yield的过程中就算出现异常文件也能正常关闭当然这里也能处理异常使用 try/except/finally 即可。
通过with语句执行
with open_file(file.txt, w) as f:print(正在写入...)f.write(Hello)执行结果跟之前的上下文管理器执行结果一致说明contextmanager装饰器也能定义一个上下文管理器。
参考
https://mp.weixin.qq.com/s?__bizMzAxMjUyNDQ5OAmid2653557641idx2snfb26d2f9a4b3e0ec707e7da19aee9a29chksm806e3d34b719b422fedf9feffa136ddef2d638b59c80921764d60d22b283bc86aae93bfc1c7dscene27