上下文管理器

上下文管理器是实现了上下文管理协议的对象,其特有的语法是“with …as”。主要用于保存和恢复各种全局状态,关闭文件等,并为try…except…finally提供了一个方便使用的封装。

上下文管理协议具体来说就是在类里面实现以下两个方法:

_enter_(): 从该方法进入运行时上下文,并返回当前对象或者与运行时上下文相关的其他对象。如果with语句有as关键词存在,返回值会绑定在as后的变量上。

_exit_(exc_type, exc_val, exc_tb): 退出运行时上下文,return True 如果 with 执行体有异常,则不会继续向上抛出异常;return Flase 如果 with 执行体有异常,则继续向上抛出异常。如果在执行with语句体时发生异常,那退出时参数会包括异常类型、异常值、异常追踪信息,否则,3个参数都是None。
下面,我们可以自己定义一个类来通过with进行上下文管理:

class MyContextManager:

    def __enter__(self):
print("connect to contextmanager")
return self # return返回的可以是对象,会绑定给as后面的变量 def __exit__(self, exc_type, exc_val, exc_tb):
"""__exit__方法中:
1.如果return False:执行query_data方法有异常,则异常继续往上抛
2.如果return True:执行query_data方法有异常,则异常不会往上抛
"""
print('close the contextmanager')
# return False
return True def query_data(self):
print('query data') with MyContextManager() as m:
m.query_data()

执行以上代码,运行结果如下:

下面,我们在类的query_data方法中增加一个报错的a,当__exit__方法 return True 时,如下:

class MyContextManager:

    def __enter__(self):
print("connect to contextmanager")
return self # return返回的可以是对象,会绑定给as后面的变量 def __exit__(self, exc_type, exc_val, exc_tb):
"""__exit__方法中:
1.如果return False:执行query_data方法有异常,则异常继续往上抛
2.如果return True:执行query_data方法有异常,则异常不会往上抛
"""
print('close the contextmanager')
# return False
return True def query_data(self):
a
print('query data') with MyContextManager() as m:
m.query_data()

运行结果如下:并不会执行 query_data() 方法

当__exit__方法 return False 时,如下:

class MyContextManager:

    def __enter__(self):
print("connect to contextmanager")
return self # return返回的可以是对象,会绑定给as后面的变量 def __exit__(self, exc_type, exc_val, exc_tb):
"""__exit__方法中:
1.如果return False:执行query_data方法有异常,则异常继续往上抛
2.如果return True:执行query_data方法有异常,则异常不会往上抛
"""
print('close the contextmanager')
return False
# return True def query_data(self):
a
print('query data') with MyContextManager() as m:
m.query_data()

运行结果如下:会抛异常,

实际应用示例:

创建一个上下文管理器,这个上下文管理器将会创建一个SQLite数据库连接,当任务处理完毕,将会将其关闭。

import sqlite3

class DataConn:
def __init__(self,db_name):
self.db_name = db_name def __enter__(self):
self.conn = sqlite3.connect(self.db_name)
return self.conn def __exit__(self,exc_type,exc_val,exc_tb):
self.conn.close()
if exc_val:
raise if __name__ == "__main__":
db = "test/test.db"
with DataConn(db) as conn:
cursor = conn.cursor()

在上面的代码中,我们创建了一个类,获取到SQLite数据库文件的路径。__enter__方法将会自动执行,并返回数据库连接对象。现在我们已经获取到数据库连接对象,然后我们创建光标,向数据库写入数据或者对数据库进行查询。当我们退出with语句的时候,它将会调用__exit__方法用于执行和关闭这个连接。

Python的内建模块 contextlib

对于上下文的管理,python也提供了内建的模块contextlib来实现相同的机制,而且这种通过生成器和装饰器实现的上下文管理器,看起来比with语句和手动实现上下文管理协议更优雅。

from contextlib import contextmanager

class MyContextManager:
def query_data(self):
# a
print('query data') @ contextmanager # 有了contextmanager我们就不需要手动实现enter和exit方法
def make_context_manager():
print('connect to contextmanager')
yield MyContextManager() # yield就相当于return,但是不会结束函数,而是暂时挂起,如果我们后续需要的话,继续调用这个函数,会从上次挂起的地方继续执行
print('close the contextmanager') with make_context_manager() as mc:
mc.query_data()

最新文章

  1. 关于JavaScript初级的知识点一(持续更新 )
  2. js中排序问题总结
  3. Python之路,day5-Python基础
  4. CentOS5.4下安装codeblocks 12.11
  5. ios 动态设置Cell高低
  6. MVC 5 Ajax + bootstrap+ handle bar 例: 实现service 状态
  7. DOS头分析
  8. javaWeb学习总结(7)- 使用Session防止表单重复提交
  9. 《高性能Mysql》翻译错误
  10. 2018年秋季学期《c语言程序设计》助教总结
  11. 自己用的Xshell配色方案
  12. Log4j使用笔记
  13. java学习笔记21(迭代器)
  14. 将Azure计算机视觉添加到Xamarin应用程序简单体验
  15. C#基础知识回顾---你不知道的Lazy<T>
  16. iOS用全局宏的概念理解xcode中的设置 preprocessor macros
  17. Spring解决Hibernate中的懒加载问题
  18. jenkins与SonarQube集成
  19. ORTP库移植
  20. Codeforces Round #298 (Div. 2)A B C D

热门文章

  1. 分享项目中在用的asp.net下载业务的服务端基类(支持客户端显示下载百分比进度,支持并发数控制,支持限速)
  2. Python网络爬虫get方法出现乱码的解决的三种方案
  3. appium如何连接多台设备
  4. Coolify系列02-从0到1超详细手把手教你上手Coolify
  5. 标准if-else语句-扩展if-else语句
  6. CSS-@规则(At-rules)常用语法使用总结
  7. drf-day6——九个视图子类、视图集、路由系统、认证组件
  8. KingbaseES libstdc++.so.6/ version 'CXXABI_1.3.8'问题处理
  9. KingbaseES数据库目录结构
  10. day07-SpringMVC底层机制简单实现-03