python上下文管理
一、python上下文介绍:
python中的上下文,指的就是代码所执行的环境状态,或者运行的场景
python上下文管理器规定了某个对象的使用范围,当进入或者离开了使用范围,会有相应的操作,多用于资源的分配和释放上,即在开始时分配资源,结束时释放资源。
如文件的读写,在读写前,需要先打开文件,在读写完成后,需要关闭文件。再如数据库的操作,在操作前,需要先连接数据库,结束后,需要释放连接等。
二、上下文管理器的使用:
下面看看资源的创建和释放场景(以数据库的操作为例):
class DataBase(object): def __init__(self): self.connect = False
def connect(self): self.connect = True
def close(self):
self.connect = False
def query(self):
if self.connect:
return "query data"
else:
raise ValueError("db not connected") def handle_query():
db = DataBase()
db.connect()
print("db query:", db.query())
db.close() if __name__=="__main__":
handle_query()
上述代码很简单,针对数据类DataBase,我们提供了connect,close,query三个常规的db交互接口。
普通的功能实现是没有问题的,但是我们都知道,在web交互中,数据库的操作是最频繁的,也就是说,我们每次在操作数据库的时候,都需要进行数据库类实例化,连接,关闭操作。显然这个和pythonic不符合的。
然后为了上面的代码更加的优雅,我们想到了python中的一个黑魔法,装饰器。
我们可以将上述代码数据库的连接和关闭封装成一个闭包,然后通过装饰器对上面的代码进行改写:
class DataBase(object):
def __init__(self):
self.connect = False
def conn(self):
self.connect = True
def close(self):
self.connect = False
def query(self):
if self.connect:
return "query data"
else:
raise ValueError("db not connected") def dbconn(fun):
def wrapper(*args, **kwargs):
db = DataBase()
db.conn()
fun(db, *args, **kwargs)
db.close()
return wrapper @dbconn
def handle_query(db=None):
print("query:", db.query) if __name__=="__main__":
handle_query()
我们封装了一个dbconn的装饰器,通过使用@dbconn装饰器,实现了数据库连接和释放的代码的复用,对比上面的代码,可以发现,使用装饰器相对优雅了很多
但是每个装饰器都需要先定义一下db的资源句柄,看起来还是没有那么优雅。下面我们通过上下文管理器的方式实现数据库操作:
class DataBase(object):
def __init__(self):
self.connect = False
def conn(self):
self.connect = True
def close(self):
self.connect = False
def query(self):
return "query data"
def __enter__(self):
self.conn()
return self
def __exit__(self, exc_type, exc_value, exc_db):
self.close() def handle_query():
with DataBase() as db:
print("query:", db.query) if __name__=="__main__":
handle_query()
对比上面的上下文管理器实现数据库操作的代码,可以发现,在定义数据库类DataBase的时候,虽然多写了几行代码,但是我们的代码可读性变得更好了。
三、上下文管理协议
实现了上下文协议的对象叫上下文管理器
那么什么是上下文协议呢?即实现了__enter__() 和__exit__()方法,也就是实现了上下文管理协议
上下文表达式必须要返回一个上下文管理器对象
代码结构如下:
class Context:
def __init__(self, filename, fileMode="w"):
self.obj = open(filename, fileMode)
def __enter__(self):
return self.obj
def __exit__(self, exc_type, exc_value, exc_db):
self.obj.close() with Context("C:\Users\admin\Desktop\1.txt") as f:
f.write("something")
如上图,Context类实现了__enter__和__exit__两个上下文管理器协议,当Context被调用或实例化的时候,创建了上下文管理器
配合with语句使用的时候,上下文管理器会自动调用__enter__方法,然后进入运行时上下文环境,并将__enter__函数返回值赋值给as从句变量 f
当f.write("something")执行完毕退出with语句块或者是出现异常导致程序退出时,会执行__exit__方法,并把异常信息传递给后面的参数exc_type, exc_value, exc_db
如果__exit__方法返回True,则with语句块不会显示的抛出异常,程序终止
如果__exit__方法返回None或者False,异常会被主动抛出,程序终止。
四、上下文管理器工具
python为了使代码更加的优雅,还提供了一个模块contextlib 来实现更函数式的上下文管理器
from contextlib import contextmanager @contextmanager
def context(filename, fileMode="w"):
f = open(filename, fileMode)
try:
yield f
except Exception as e:
print(e)
finally:
f.close() with context("C:\\Users\\admin\\Desktop\\1.txt") as f:
f.write("write something1")
上图通过contextmanager装饰器定义了一个上下文管理器函数context,通过with context("C:\\Users\\admin\\Desktop\\1.txt") 返回上下文管理器对象
然后调用函数隐式的__enter__函数,并将结果通过yield返回
然后通过返回的文件对象,执行文件的写入操作
写入操作结束,退出上下文环境,执行了f.close()
五、with语句执行过程总结:
1)执行上下文表达式 Context("C:\Users\admin\Desktop\1.txt"),获得上下文管理器
2)加载上下文管理器的__enter__ 和 __exit__,以备后续调用
3)调用__enter__(),方法,并返回文件对象 f 赋值给as从句变量
4)执行with语句块的子语句块f.write("something")
5)调用上下文管理器的__exit__(),如果是由于异常导致程序退出的,将type, value 和traceback作为参数传递给exit(),否则传三个None
如果__exit__()返回值等于False,则异常会被显示的抛出,程序终止,否则,异常会被无视,继续执行。
上下文管理器主要用于多线程/进程的变成中,因为涉及到上下文的切换
python上下文管理的更多相关文章
- python 上下文管理器
作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 上下文管理器(context manager)是Python2.5开始支持的一种语 ...
- Python 上下文管理器和else块
最终,上下文管理器可能几乎与子程序(subroutine)本身一样重要.目前,我们只了解了上下文管理器的皮毛--Basic 语言有with 语句,而且很多语言都有.但是,在各种语言中 with 语句的 ...
- Python上下文管理器
在Python中让自己创建的函数.类.对象支持with语句,就实现了上线文管理协议.我们经常使用with open(file, "a+") as f:这样的语句,无需手动调用f.c ...
- python上下文管理器ContextLib及with语句
http://blog.csdn.net/pipisorry/article/details/50444736 with语句 with语句是从 Python 2.5 开始引入的一种与异常处理相关的功能 ...
- Python上下文管理器 with
对于系统资源的操作,如:文件操作.数据库操作等,我们往往打开文件.连接数据库后忘了将其close掉,这时就可能会引发异常,因此我们常用的做法是: # coding:utf-8 f = open(&qu ...
- Python上下文管理协议:__enter__和__exit__
上下文管理器(context manager)是Python2.5开始支持的一种语法,用于规定某个对象的使用范围.一旦进入或者离开该使用范围,会有特殊操作被调用 (比如为对象分配或者释放内存).它的语 ...
- Python上下文管理器(Context managers)
上下文管理器(Context managers) 上下文管理器允许你在有需要的时候,精确地分配和释放资源. 使用上下文管理器最广泛的案例就是with语句了.想象下你有两个需要结对执行的相关操作,然后还 ...
- python上下文管理器细读
test 1 上下文管理器,将生成器转化为上下文管理器 import contextlib @contextlib.contextmanager def a(): print(1) yield pri ...
- 吃透Python上下文管理器
什么是上下文管理器? 我们常见的with open操作文件,就是一个上下文管理器.如: with open(file, 'rb') as f: text = f.read() 那上下文管理器具体的定义 ...
随机推荐
- 记一发idea resources下rename的坑
resources rename文件 '.'不表示下级目录 只是作为一个字符 第一个com.uniubi.dao 是一层层创的.第二个是直接用idea 创的如下图. maven 打包后如下所示. ps ...
- 为什么不要使用 async void?
问题 在使用 Abp 框架的后台作业时,当后台作业抛出异常,会导致整个程序崩溃.在 Abp 框架的底层执行后台作业的时候,有 try/catch 语句块用来捕获后台任务执行时的异常,但是在这里没有生效 ...
- 【机器学习】--模型评估指标之混淆矩阵,ROC曲线和AUC面积
一.前述 怎么样对训练出来的模型进行评估是有一定指标的,本文就相关指标做一个总结. 二.具体 1.混淆矩阵 混淆矩阵如图: 第一个参数true,false是指预测的正确性. 第二个参数true,p ...
- mysql的学习笔记(二)
1.数据类型,存储的类型. 整型 TINYINT 有符号-128到127 无符号值:0到255 1字节 SMALLINT 有符号 -32768到32767 0到65535 2字节 MEDIUMINT ...
- 如何面对被抛弃的System.Data.OracleClient
Visual Studio2012连接访问ORACLE数据库 近些年因工作内容的转变,很少去编码了.一些简单的需求使用VS+SQL SERVER这对老搭档便可快捷而舒服的搞定.只是近日需要管理一些OR ...
- Vue.js-03:第三章 - 事件修饰符的使用
一.前言 熟悉了 Vue 的指令系统后,在实际开发中,不可避免的会使用到对于事件的操作,如何处理 DOM 事件流,成为我们必须要掌握的技能.不同于传统的前端开发,在 Vue 中给我们提供了事件修饰符这 ...
- 在Linux系统配置Nodejs环境的最简单步骤,部署多个thinkjs(nodejs)项目
发现一台服务器部署管理多个nodejs服务,可以采用二级域名weekly.mwcxs.top,也可以采用固定后缀www.mwcxs.top/weekly的方式,本文先从固定后缀的方式部署管理多个nod ...
- 《前端之路》之 operator 操作符的优先级
Github传送门,欢迎 Star - - Github地址,欢迎 Star
- springcloud~Eureka实例搭建
服务端 build.gradle配置 dependencies { compile('org.springframework.cloud:spring-cloud-starter-netflix-eu ...
- 手撸GitLab CI(阉割版)
上一集我们说到如何从零开始搭建一个Vue-cli 3.0的项目,而这一集我们将说到如何手写一份阉割版的CI脚本. 首先说一下GitLab部署到服务器的操作,一般有两种,一种是规范化分离的,包含runn ...