Python 中的关键字with详解
(转载)http://yuez.me/python-zhong-de-guan-jian-zi-with-xiang-jie/
在 Python 2.5 中,with
关键字被加入。它将常用的 try ... except ... finally ...
模式很方便的被复用。看一个最经典的例子:
1 2 |
|
在这段代码中,无论with
中的代码块在执行的过程中发生任何情况,文件最终都会被关闭。如果代码块在执行的过程中发生了一个异常,那么在这个异常被抛出前,程序会先将被打开的文件关闭。
再看另外一个例子。
在发起一个数据库事务请求的时候,经常会用类似这样的代码:
1 2 3 4 5 6 7 8 9 |
|
如果将发起事务请求的操作变成可以支持with
关键字的,那么用像这样的代码就可以了:
1 2 |
|
下面,详细的说明一下with
的执行过程,并用两种常用的方式实现上面的代码。
with 的一般执行过程
一段基本的with
表达式,其结构是这样的:
1 2 |
|
其中:EXPR
可以是任意表达式;as VAR
是可选的。其一般的执行过程是这样的:
- 计算
EXPR
,并获取一个上下文管理器。 - 上下文管理器的
__exit()__
方法被保存起来用于之后的调用。 - 调用上下文管理器的
__enter()__
方法。 - 如果
with
表达式包含as VAR
,那么EXPR
的返回值被赋值给VAR
。 - 执行
BLOCK
中的表达式。 - 调用上下文管理器的
__exit()__
方法。如果BLOCK
的执行过程中发生了一个异常导致程序退出,那么异常的type
、value
和traceback
(即sys.exc_info()
的返回值)将作为参数传递给__exit()__
方法。否则,将传递三个None
。
将这个过程用代码表示,是这样的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
这个过程有几个细节:
- 如果上下文管理器中没有
__enter()__
或者__exit()__
中的任意一个方法,那么解释器会抛出一个AttributeError
。 - 在
BLOCK
中发生异常后,如果__exit()__
方法返回一个可被看成是True
的值,那么这个异常就不会被抛出,后面的代码会继续执行。
接下来,用两种方法来实现上面来实现上面的过程的吧。
实现上下文管理器类
第一种方法是实现一个类,其含有一个实例属性db
和上下文管理器所需要的方法__enter()__
和__exit()__
。
1 2 3 4 5 6 7 8 9 10 11 12 |
|
了解with
的执行过程后,这个实现方式是很容易理解的。下面介绍的实现方式,其原理理解起来要复杂很多。
使用生成器装饰器
在Python的标准库中,有一个装饰器可以通过生成器获取上下文管理器。使用生成器装饰器的实现过程如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
第一眼上看去,这种实现方式更为简单,但是其机制更为复杂。看一下其执行过程吧:
- Python解释器识别到
yield
关键字后,def
会创建一个生成器函数替代常规的函数(在类定义之外我喜欢用函数代替方法)。 - 装饰器
contextmanager
被调用并返回一个帮助函数,这个帮助函数在被调用后会生成一个GeneratorContextManager
实例。最终with
表达式中的EXPR
调用的是由contentmanager
装饰器返回的帮助函数。 with
表达式调用transaction(db)
,实际上是调用帮助函数。帮助函数调用生成器函数,生成器函数创建一个生成器。- 帮助函数将这个生成器传递给
GeneratorContextManager
,并创建一个GeneratorContextManager
的实例对象作为上下文管理器。 with
表达式调用实例对象的上下文管理器的__enter()__
方法。__enter()__
方法中会调用这个生成器的next()
方法。这时候,生成器方法会执行到yield db
处停止,并将db
作为next()
的返回值。如果有as VAR
,那么它将会被赋值给VAR
。with
中的BLOCK
被执行。BLOCK
执行结束后,调用上下文管理器的__exit()__
方法。__exit()__
方法会再次调用生成器的next()
方法。如果发生StopIteration
异常,则pass
。- 如果没有发生异常生成器方法将会执行
db.commit()
,否则会执行db.rollback()
。
再次看看上述过程的代码大致实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
|
总结
Python的with
表达式包含了很多Python特性,花点时间吃透with
是一件非常值得的事情。
一些其他的例子
锁机制
1 2 3 4 5 6 7 |
|
标准输出重定向
1 2 3 4 5 6 7 8 9 10 11 12 |
|
引用
- The Python “with” Statement by Example
- PEP 343
Python 中的关键字with详解相关推荐
- 站长在线Python教程精讲:在Python函数中的关键字参数详解
欢迎你来到站长在线的站长学堂学习Python知识,本文学习的是<在Python函数中的关键字参数详解>.本文的主要内容有:关键字参数的含义和关键字参数的应用举例. 目录 1.关键字参数的含 ...
- python中的super用法详解_【Python】【类】super用法详解
一.问题的发现与提出 在Python类的方法(method)中,要调用父类的某个方法,在Python 2.2以前,通常的写法如代码段1: 代码段1: class A: def __init__(sel ...
- Python中的高级数据结构详解
这篇文章主要介绍了Python中的高级数据结构详解,本文讲解了Collection.Array.Heapq.Bisect.Weakref.Copy以及Pprint这些数据结构的用法,需要的朋友可以参考 ...
- python中的super用法详解_Python中super函数用法实例分析
本文实例讲述了python中super函数用法.分享给大家供大家参考,具体如下: 这是个高大上的函数,在python装13手册里面介绍过多使用可显得自己是高手 23333. 但其实他还是很重要的. 简 ...
- python classmethod_对Python中的@classmethod用法详解
在Python面向对象编程中的类构建中,有时候会遇到@classmethod的用法. 总感觉有这种特殊性说明的用法都是高级用法,在我这个层级的水平中一般是用不到的. 不过还是好奇去查了一下. 大致可以 ...
- python中 xlrd/xlwt模块详解
python中 xlrd/xlwt模块详解 1.什么是xlrd模块 python操作excel主要用到xlrd和xlwt两个库,即xlrd是读excel,xlwt是写excel库 一.安装xlrd模块 ...
- C++中const关键字用法详解及实例和源码下载(一)
最近在学习C++基础部分,看了两天书,已经看过了一遍,半知半解,回过头来重新看第二遍,深入了解一下C++的基础知识.现在读到了const关键字的用法,书上面讲解的时候并没有给出完整的实例,只是理论的讲 ...
- Python中的bbox_overlaps()函数详解
Python中的bbox_overlaps()函数详解 想要编写自己的目标检测算法,就需要掌握bounding box(边界框)之间的关系.在这之中,bbox_overlaps()函数是一个非常实用的 ...
- 站长在线Python精讲:在Python中函数的调用详解
欢迎你来到站长在线的站长学堂学习Python知识,本文学习的是<在Python中函数的调用详解>.本文的主要内容有:调用函数的基本语法和调用自定义函数的实例讲解. 目录 1.调用函数的基本 ...
- 站长在线Python精讲:Python中正则表达式的语法详解
欢迎你来到站长在线的站长学堂学习Python知识,本文学习的是<Python中正则表达式的语法详解>.本知识点主要内容有9点:行定位符.元字符.限定符.字符集.排除字符.选择字符.转义字符 ...
最新文章
- var和dynamic的应用 var、动态类型 dynamic 深入浅析C#中的var和dynamic ----demo
- python中map函数运行原理_Python中map函数的解释和可视化
- 《Shell脚本学习指南》第一章 背景知识
- Objective-C 内存管理机制
- linux下面拷贝gbk编码的网页
- python简单应用题_Python简单应用题
- Spring Boot笔记-@Scheduled(cron=““)设置调度任务
- 命令行远程链接MySQL
- 10个最好的 Node.js MVC 框架
- 吉利嘉际车机安装第三方软件教程(2022年更新)
- Excel任务该如何在FineReader 12中设置
- java开发的格式与书写规范
- CDA数据分析师-LEVEL I考试-分享
- 使用Blast2GO进行GO注释
- Javascript阻止事件冒泡和浏览器默认行为
- python 中搞错工作路径的意思导致的相对路径产生bug:[Errno 2] No such file or directory:
- OpenCV开发笔记(六十四):红胖子8分钟带你深入了解SURF特征点(图文并茂+浅显易懂+程序源码)
- 005-电脑软件安装包20190408
- unbound部署DNS服务器
- excel用VBA插入列号
热门文章
- C# 使用Magick.NET进行图片格式转换,修改尺寸(.ico .jpg .png .gif .bmp),解决png转jpg透明变黑底问题
- linux shell有哪些变量,Linux Bash Shell有关变量
- java Web中实现QQ邮箱验证以及验证码注册用户
- C64x EDMA Architecture
- IEC61850和IEC60870-6(TASE.2)的比较
- 腾讯云与玉符科技达成战略合作 共建SaaS生态统一身份认证体系
- 手把手教你7个常见数据库使用方法
- python pymysql模块下载_python开发11之PyMySQL模块
- java的泛型方法_Java中的泛型方法
- 关于2020年各省市GDP和各省人均GDP的探索