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 文件重命名工具代码
Jul 26 Python
Python标准库与第三方库详解
Jul 22 Python
从Python的源码来解析Python下的freeblock
May 11 Python
WINDOWS 同时安装 python2 python3 后 pip 错误的解决方法
Mar 16 Python
Pycharm学习教程(3) 代码运行调试
May 03 Python
Python中如何优雅的合并两个字典(dict)方法示例
Aug 09 Python
python中map的基本用法示例
Sep 10 Python
对django xadmin自定义菜单的实例详解
Jan 03 Python
python 实现读取一个excel多个sheet表并合并的方法
Feb 12 Python
对Python中class和instance以及self的用法详解
Jun 26 Python
Python函数式编程指南:对生成器全面讲解
Nov 19 Python
给ubuntu18安装python3.7的详细教程
Jun 08 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
让的PHP代码飞起来的40条小技巧(提升php效率)
2010/04/12 PHP
php中突破基于HTTP_REFERER的防盗链措施(stream_context_create)
2011/03/29 PHP
初品cakephp 入门基础
2012/02/16 PHP
php禁止某ip或ip地址段访问的方法
2015/02/25 PHP
PHP将英文数字转换为阿拉伯数字实例讲解
2019/01/28 PHP
List the Codec Files on a Computer
2007/06/18 Javascript
JQUERY 获取IFrame中对象及获取其父窗口中对象示例
2013/08/19 Javascript
node.js中的buffer.length方法使用说明
2014/12/14 Javascript
JavaScript中的console.log()函数详细介绍
2014/12/29 Javascript
javascript设计模式之中介者模式Mediator
2014/12/30 Javascript
浅析AngularJS中的生命周期和延迟处理
2015/06/18 Javascript
js+css实现文字散开重组动画特效代码分享
2015/08/21 Javascript
js表单中选择框值的获取及表单的序列化
2015/12/17 Javascript
简单实现js页面切换功能
2021/01/10 Javascript
js仿京东轮播效果 选项卡套选项卡使用
2017/01/12 Javascript
javascript获取以及设置光标位置
2017/02/16 Javascript
javascript 数据存储的常用函数总结
2017/06/01 Javascript
angular $watch 一个变量的变化(实例讲解)
2017/08/02 Javascript
详解设置Webstorm 利用babel将ES6自动转码成ES5
2017/12/20 Javascript
JS实现自定义弹窗功能
2018/08/08 Javascript
详解ES6 Promise的生命周期和创建
2019/08/18 Javascript
JS操作Fckeditor的一些常用方法(获取、插入等)
2020/02/19 Javascript
python通过scapy获取局域网所有主机mac地址示例
2014/05/04 Python
python如何查看系统网络流量的信息
2016/09/12 Python
python自带的http模块详解
2016/11/06 Python
Java文件与类动手动脑实例详解
2019/11/10 Python
tensorflow生成多个tfrecord文件实例
2020/02/17 Python
python和go语言的区别是什么
2020/07/20 Python
python3.7 openpyxl 在excel单元格中写入数据实例
2020/09/01 Python
中医专业应届生求职信
2013/11/17 职场文书
小学安全教育材料
2014/02/17 职场文书
考研英语复习计划
2015/01/19 职场文书
计划生育个人总结
2015/03/02 职场文书
Mysql实现简易版搜索引擎的示例代码
2021/08/30 MySQL
SpringBoot 集成短信和邮件 以阿里云短信服务为例
2022/04/22 Java/Android
win7配置本地ftp服务器的图文教程
2022/08/05 Servers