Python上下文管理器类和上下文管理器装饰器contextmanager用法实例分析


Posted in Python onNovember 07, 2019

本文实例讲述了Python上下文管理器类和上下文管理器装饰器contextmanager用法。分享给大家供大家参考,具体如下:

一. 什么是上下文管理器

上下文管理器是在Python2.5之后加入的功能,可以在方便的需要的时候比较精确地分配和释放资源, with便是上下文管理器的最广泛的应用, 比如:

with open("test/test.txt","w") as f:
 f.write("hello")

这上会比使用try:...finally:f.close方便的多.

二. 自定义一个上下文管理器类:

class MyResource:
  # __enter__ 返回的对象会被with语句中as后的变量接受
  def __enter__(self):
    print('connect to resource')
    return self

  def __exit__(self, exc_type, exc_value, tb):
    print('close resource conection')

  def query(self):
    print('query data')

类中有两个特殊的魔术方法:

  • __enter__: with语句中的代码块执行前, 会执行__enter__, 返回的值将赋值给with句中as后的变量.
  • __exit__: with语句中的代码块执行结束或出错, 会执行_exit__

比如以下代码:

with Myresource() as r:
  r.query()

的打印结果为:

connect to resource
query data
close resource conection

那么有没有一个简化定义的方法呢, python提供了一个装饰器contextmanager

三. 使用contextmanager

from contextlib import contextmanager
class MyResource:
  def query(self):
    print('query data')
@contextmanager
def make_myresource():
  print('start to connect')
  yield MyResource()
  print('end connect')
  pass

被装饰器装饰的函数分为三部分:

  1. with语句中的代码块执行前执行函数中yield之前代码
  2. yield返回的内容复制给as之后的变量
  3. with代码块执行完毕后执行函数中yield之后的代码

比如下方代码:

with make_myresource() as r:
   r.query()

的结果为:

start to connect
query data
end connect

四. 一个例子, sqlalchemy: 数据库的自动提交和回滚

在编程中如果频繁的修改数据库, 一味的使用类似try:... except..: rollback() raise e其实是不太好的.

比如某一段的代码的是这样的:

try:
    gift = Gift()
    gift.isbn = isbn
    ... 
    db.session.add(gift)
    db.session.commit()
  except Exception as e:
    db.session.rollback()
    raise e

为了达到使用with语句的目的, 我们可以重写db所属的类:

from flask_sqlalchemy import SQLAlchemy as _SQLALchemy
class SQLAlchemy(_SQLALchemy):
  @contextmanager
  def auto_commit(self):
    try:
      yield
      self.session.commit()
    except Exception as e:
      db.session.rollback()
      raise e

这时候, 在执行数据的修改的时候便可以:

with db.auto_commit():
    gift = Gift()
    gift.isbn = isbndb.session.add(gift)
    db.session.add(gift)

with db.auto_commit():
  user = User()
  user.set_attrs(form.data)
  db.session.add(user)

关于Python相关内容感兴趣的读者可查看本站专题:《Python函数使用技巧总结》、《Python面向对象程序设计入门与进阶教程》、《Python数据结构与算法教程》、《Python字符串操作技巧汇总》、《Python编码操作技巧总结》及《Python入门与进阶经典教程》

希望本文所述对大家Python程序设计有所帮助。

Python 相关文章推荐
用Python编写一个每天都在系统下新建一个文件夹的脚本
May 04 Python
Python赋值语句后逗号的作用分析
Jun 08 Python
Python读写Json涉及到中文的处理方法
Sep 12 Python
Python 数据结构之旋转链表
Feb 25 Python
Python连接SQLServer2000的方法详解
Apr 19 Python
python方法生成txt标签文件的实例代码
May 10 Python
详解Python3除法之真除法、截断除法和下取整对比
May 23 Python
django数据库自动重连的方法实例
Jul 21 Python
python 爬取疫情数据的源码
Feb 09 Python
TensorFLow 变量命名空间实例
Feb 11 Python
python查找特定名称文件并按序号、文件名分行打印输出的方法
Apr 24 Python
Python中json.dumps()函数的使用解析
May 17 Python
Python中xml和dict格式转换的示例代码
Nov 07 #Python
python对象转字典的两种实现方式示例
Nov 07 #Python
python多线程高级锁condition简单用法示例
Nov 07 #Python
python文件操作的简单方法总结
Nov 07 #Python
详解Django admin高级用法
Nov 06 #Python
Python全局锁中如何合理运用多线程(多进程)
Nov 06 #Python
Python实现socket非阻塞通讯功能示例
Nov 06 #Python
You might like
《Re:从零开始的异世界生活 冰结之绊》
2020/04/09 日漫
PHP 服务器配置(使用Apache及IIS两种方法)
2009/06/01 PHP
解析关于java,php以及html的所有文件编码与乱码的处理方法汇总
2013/06/24 PHP
destoon实现商铺管理主页设置增加新菜单的方法
2014/06/26 PHP
php Session无效分析资料整理
2016/11/29 PHP
深入理解JavaScript系列(4) 立即调用的函数表达式
2012/01/15 Javascript
JS实现的省份级联实例代码
2013/06/24 Javascript
jQuery中filter()和find()的区别深入了解
2013/09/25 Javascript
javascript设置连续两次点击按钮时间间隔的方法
2014/10/28 Javascript
谈谈encodeURI和encodeURIComponent以及escape的区别与应用
2015/11/24 Javascript
网页前端登录js按Enter回车键实现登陆的两种方法
2016/05/10 Javascript
jQuery AJAX timeout 超时问题详解
2016/06/21 Javascript
jquery,js简单实现类似Angular.js双向绑定
2017/01/13 Javascript
基于MVC方式实现三级联动(JavaScript)
2017/01/23 Javascript
JS验证input输入框(字母,数字,符号,中文)
2017/03/23 Javascript
Web前端框架Angular4.0.0 正式版发布
2017/03/28 Javascript
Vue实现购物车功能
2017/04/27 Javascript
JavaScript闭包和回调详解
2017/08/09 Javascript
Vue实现搜索 和新闻列表功能简单范例
2018/03/16 Javascript
JavaScript实现飞舞的泡泡效果
2020/02/07 Javascript
微信小程序实现菜单左右联动
2020/05/19 Javascript
Vant picker 多级联动操作
2020/11/02 Javascript
[51:36]Optic vs Newbee 2018国际邀请赛小组赛BO2 第一场 8.17
2018/08/18 DOTA
python实现Decorator模式实例代码
2018/02/09 Python
python根据list重命名文件夹里的所有文件实例
2018/10/25 Python
PySide和PyQt加载ui文件的两种方法
2019/02/27 Python
django重新生成数据库中的某张表方法
2019/08/28 Python
python线程池 ThreadPoolExecutor 的用法示例
2020/10/10 Python
python爬虫中PhantomJS加载页面的实例方法
2020/11/12 Python
劳动竞赛口号
2014/06/16 职场文书
慰问信范文
2015/02/14 职场文书
2015年高考寄语或鼓励的话
2015/03/23 职场文书
2015年施工员工作总结范文
2015/04/20 职场文书
MySQL命令行操作时的编码问题详解
2021/04/14 MySQL
python中对列表的删除和添加方法详解
2022/02/24 Python
详解Flutter和Dart取消Future的三种方法
2022/04/07 Java/Android