Python_上下文管理器
上下文管理器(context manager)是 Python 编程中的重要概念,用于规定某个对象的使用范围。一旦进入或者离开该使用范围,会有特殊操作被调用 (比如为对象分配或者释放内存)。它的语法形式是with...as...
为了确保一些系统资源得以正确释放,我们经常会用到 try ... excepte ... finally 语句。如:
- try:
- f = open('somefile')
- for line in f:
- print(line)
- except Exception as e:
- print(e)
- finally:
- f.close()
上面的代码模式,从用复用代码的模式来讲,并不够好。于是 with 语句出现了,通过定义一个上下文管理器来封装这个代码块:
- with open('filename', 'r') as f:
- for line in f:
- print(line)
显然,with 语句比 try 语句简洁了许多。
上下文管理器类
由于 with 语句利用了上下文管理器,在深入理解 with 语句之前,我们先看看上下文管理器。我们要定义一个上下文管理器其实很简单,只要一个类实现了__enter__(self)和__exit__(self, exc_type, exc_valye, traceback)我们就叫他上下文管理器
__enter__(self) 返回一个对象,可以是当前类的实例,也可以是其他对象。
- class SomeThing:
- def __enter__(self):
- return self # 返回类实例
- class LineLength:
- def __init__(self, filepath):
- self.__file = open(self.__filepath)
- def __enter__(self):
- return self.__file # 返回其他对象
执行过程
下面让我们看看 with 语句具体是如何执行的。
第一步:执行上下文表达式以获得上下文管理器对象。上下文表达式就是 with 和 as 之间的代码。
第二步:加载上下文管理器对象的 __exit__()方法备用。
第三步:执行上下文管理器对象的__enter__()方法。
第四步:将__enter__()方法返回值绑定到 as 后面的 变量中。
第五步:执行 with 内的代码块。
第六步:执行上下文管理器的__exit__()方法。
如果在代码块中发生了异常,异常被传入__exit__()中。如果没有,__exit__()的三个参数会传入 None, None, None。__exit__()需要明确地返回 True 或 False。并且不能在__exit__()中再次抛出被传入的异常,这是解释器的工作,解释器会根据返回值来确定是否继续向上层代码传递异常。当返回 True 时,异常不会被向上抛出,代码会从报异常的代码处跳出上下文管理继续执行代码,当返回 False 时会向上抛出,阻断代码执行。当没有异常发生传入__exit__()时,解释器会忽略返回值。
- import time
- class File(object):
- def __init__(self, filename, mode):
- print("上下文管理执行顺序:\n1、执行初始化方法")
- self.f = open(filename, mode)
- def __enter__(self):
- print("2、执行__enter__()方法")
- return self # "__enter__()方法的返回值绑定到 as 后面的 变量中
- def __exit__(self, exc_type, exc_val, exc_tb):
- """
- :param exc_type:如果抛出异常,返回异常类型,否则返回None
- :param exc_val:如果抛出异常,返回异常内容,否则返回None
- :param exc_tb:如果抛出异常,返回异常位置,否则返回None
- :return:
- """
- print("4、执行__exit__()方法")
- if exc_type:
- print(exc_type, "\n", exc_val, "\n", exc_tb)
- # 若代码块报错则立即执行__exit__()方法中的代码;若代码块没报错,执行完代码块后执行__exit__()方法中的代码"
- self.f.close()
- time.sleep(1)
- # return True # 当返回 True 时,异常不会被向上抛出,代码会从报异常的代码处跳出上下文管理继续执行代码,
- return False # 当返回 False 时会在__exit__()方法执行完后向上抛出,阻断代码执行。
- def reads(self):
- return self.f.read()
- with File("README.md", "rb") as f:
- print("3、执行代码块代码")
- # 代码块部分
- f.reads()
- # 代码块报错,报错后的代码不会被执行
- print("若代码块报错,“我”不被执行;将r改为rb,代码块不报错“我”就执行")
- print("若代码块报错,__exit__()方法中返回 Ture “我”才执行;若代码块不报错,“我”也执行")
执行结果:
把"rb"改为"r"后执行结果:
多上下文管理器
实际上,我们可以同时处理多个上下文管理器:
- with A() as a, B() as b:
- suite
所以我们大可不必写嵌套的 with 语句。
contextmanager实现上下文管理器
Python还提供了一个contextmanager的装饰器,更进一步简化了上下文管理器的实现方法。通过yield将函数分割成两部分,yield之前的部分相当于在__enter__方法中执行,yield之后的部分相当于在__exit__方法中执行,紧跟在yield之后的返回值给as之后的变量。
- from contextlib import contextmanager
- class File:
- def __init__(self, filename, mode):
- self.f = open(filename, mode)
- def reads(self):
- return self.f.read()
- def closed(self):
- self.f.close()
- @contextmanager
- def read_file():
- print(1)
- rf = File("README.md", "rb")
- yield rf
- print(3)
- rf.closed()
- with read_file() as f:
- print(2)
- f.reads()
执行结果:
把"rb"改为"r"后执行结果:
注:当报错后,没有打印3,不清楚yield下面的代码是否执行。
Python_上下文管理器的更多相关文章
- python2.7高级编程 笔记一(Python中的with语句与上下文管理器学习总结)
0.关于上下文管理器上下文管理器是可以在with语句中使用,拥有__enter__和__exit__方法的对象. with manager as var: do_something(var) 相当于以 ...
- 翻译《Writing Idiomatic Python》(五):类、上下文管理器、生成器
原书参考:http://www.jeffknupp.com/blog/2012/10/04/writing-idiomatic-python/ 上一篇:翻译<Writing Idiomatic ...
- python学习笔记4(对象/引用;多范式; 上下文管理器)
### Python的强大很大一部分原因在于,它提供有很多已经写好的,可以现成用的对象 21. 动态类型:对象/引用 对象和引用: 对象是储存在内存中的实体,对象名只是指向这一对象的引用(refere ...
- Python深入02 上下文管理器
作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 上下文管理器(context manager)是Python2.5开始支持的一种语 ...
- python 上下文管理器
作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 上下文管理器(context manager)是Python2.5开始支持的一种语 ...
- 【Python学习笔记】with语句与上下文管理器
with语句 上下文管理器 contextlib模块 参考引用 with语句 with语句时在Python2.6中出现的新语句.在Python2.6以前,要正确的处理涉及到异常的资源管理时,需要使用t ...
- python上下文管理器及with语句
with语句支持在一个叫上下文管理器的对象的控制下执行一系列语句,语法大概如下: with context as var: statements 其中的context必须是个上下文管理器,它实现了两个 ...
- 流畅python学习笔记:第十五章:上下文管理器
在开始本章之前,我们首先来谈谈try-excep..final模块.在Python中,进行异常保护的最多就是用try..except..final.首先来看下下面的代码.进行一个简单的除法运算.为了防 ...
- python contextlib 上下文管理器
1.with操作符 在python中读写文件,可能需要这样的代码 try-finally读写文件 file_text = None try: file_text = open('./text', 'r ...
随机推荐
- 使用fastDFS上传和下载图片文件
package com.xuecheng.test.fastdfs;import org.csource.common.MyException;import org.csource.fastdfs.* ...
- js格式化合计金额
var summoney=1040.010400000000000001; var totalMoney=parseFloat(summoney).toFixed(2); var arry=total ...
- 【JAVA今法修真】 第二章 一气化三清 线程分心念
这是我的微信公众号,希望有兴趣的朋友能够一起交流,也希望能够多多支持新人作者,你的每一份关注都是我写文章的动力:南橘ryc 天有八纪,地分九州,万法仙门与天道剑宗一并坐落在东北方通辽州. 与李小庚想象 ...
- 解决电脑连接 iPhone 热点没有 IPv6地址的问题
问题描述: 初入 iPhone ,电脑使用 ios 共享的热点无法连接 IPv6 地址.但是,直接在 iPhone 上面打开 https://www.test-ipv6.com/ 完美支持 IPv6 ...
- C# VS 调试报错:未能加载文件或程序集“Newtonsoft.Json, Version=4.5.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed”或它的某一个依赖项
今天在使用 VS(VisualStudio) 调试一个复杂的 WinForm 程序,总是提示错误: 未能加载文件或程序集"Newtonsoft.Json, Version=4.5.0.0, ...
- 数组队列如何手撕?解密ArrayBlockingQueue的实现内幕!
队列 聊起队列,你一定会联想到一个与队列相似的数据结构:栈. 为了更好的理解什么是队列,我们将它和栈来比较一下: 队列的特点是:先进先出,如下图,1先进,1就先出. 图1:队列的图解 栈的特点是:先进 ...
- LuoguP2382 化学分子式 题解
Description 你的任务是编写一个能处理在虚拟的化学里分子式的程序,具体地说,给定你所有原子的相对原子质量,求出所有询问的分子的相对分子质量,或者报告不存在. 数据范围:原子质量 \(\leq ...
- CF1469D Ceil Divisions 题解
Content 你有一个长度为 \(n\) 的数组 \(a\),初始时,\(\forall i\in[1,n]\),\(a_i=i\). 每次操作选择两个数 \(x,y(1\leqslant x,y\ ...
- 更换vue项目中标签页icon
问题:在vue项目中, 需要将标签上的icon换成自己所需的,发现在更换了public/favicon.ico后,没有生效,依旧是原来Vue的icon. 解决办法:在vue.config.js中,修改 ...
- MyBatis中比较(大于、小于)符号的转义写法
< < <= <= > > >= >= & & ' ' " & ...