Python深入学习之上下文管理器


Posted in Python onAugust 31, 2014

上下文管理器(context manager)是Python2.5开始支持的一种语法,用于规定某个对象的使用范围。一旦进入或者离开该使用范围,会有特殊操作被调用 (比如为对象分配或者释放内存)。它的语法形式是with...as...

关闭文件

我们会进行这样的操作:打开文件,读写,关闭文件。程序员经常会忘记关闭文件。上下文管理器可以在不需要文件的时候,自动关闭文件。

下面我们看一下两段程序:

# without context manager

f = open("new.txt", "w")

print(f.closed)               # whether the file is open

f.write("Hello World!")

f.close()

print(f.closed)

以及:
# with context manager

with open("new.txt", "w") as f:

    print(f.closed)

    f.write("Hello World!")

print(f.closed)

两段程序实际上执行的是相同的操作。我们的第二段程序就使用了上下文管理器 (with...as...)。上下文管理器有隶属于它的程序块。当隶属的程序块执行结束的时候(也就是不再缩进),上下文管理器自动关闭了文件 (我们通过f.closed来查询文件是否关闭)。我们相当于使用缩进规定了文件对象f的使用范围。

上面的上下文管理器基于f对象的__exit__()特殊方法(还记得我们如何利用特殊方法来实现各种语法?参看特殊方法与多范式)。当我们使用上下文管理器的语法时,我们实际上要求Python在进入程序块之前调用对象的__enter__()方法,在结束程序块的时候调用__exit__()方法。对于文件对象f来说,它定义了__enter__()和__exit__()方法(可以通过dir(f)看到)。在f的__exit__()方法中,有self.close()语句。所以在使用上下文管理器时,我们就不用明文关闭f文件了。

自定义

任何定义了__enter__()和__exit__()方法的对象都可以用于上下文管理器。文件对象f是内置对象,所以f自动带有这两个特殊方法,不需要自定义。

下面,我们自定义用于上下文管理器的对象,就是下面的myvow:

# customized object
class VOW(object):

    def __init__(self, text):

        self.text = text

    def __enter__(self):

        self.text = "I say: " + self.text    # add prefix

        return self                          # note: return an object

    def __exit__(self,exc_type,exc_value,traceback):

        self.text = self.text + "!"          # add suffix


with VOW("I'm fine") as myvow:

    print(myvow.text)
print(myvow.text)

我们的运行结果如下:

I say: I'm fine

I say: I'm fine!

我们可以看到,在进入上下文和离开上下文时,对象的text属性发生了改变(最初的text属性是"I'm fine")。

__enter__()返回一个对象。上下文管理器会使用这一对象作为as所指的变量,也就是myvow。在__enter__()中,我们为myvow.text增加了前缀 ("I say: ")。在__exit__()中,我们为myvow.text增加了后缀("!")。

注意: __exit__()中有四个参数。当程序块中出现异常(exception),__exit__()的参数中exc_type, exc_value, traceback用于描述异常。我们可以根据这三个参数进行相应的处理。如果正常运行结束,这三个参数都是None。在我们的程序中,我们并没有用到这一特性。

总结:

通过上下文管理器,我们控制对象在程序不同区间的特性。上下文管理器(with EXPR as VAR)大致相当于如下流程:

# with EXPR as VAR:
VAR = EXPR

VAR = VAR.__enter__()

try:

    BLOCK

finally:

    VAR.__exit__()

由于上下文管理器带来的便利,它是一个值得使用的工具。
Python 相关文章推荐
分析在Python中何种情况下需要使用断言
Apr 01 Python
Python遍历目录中的所有文件的方法
Jul 08 Python
解决Python 遍历字典时删除元素报异常的问题
Sep 11 Python
python递归实现快速排序
Aug 18 Python
3个用于数据科学的顶级Python库
Sep 29 Python
python的继承知识点总结
Dec 10 Python
python实现整数的二进制循环移位
Mar 08 Python
Python matplotlib绘制饼状图功能示例
Sep 10 Python
Python实现非正太分布的异常值检测方式
Dec 09 Python
python3正则模块re的使用方法详解
Feb 11 Python
基于Python中random.sample()的替代方案
May 23 Python
python的html标准库
Apr 29 Python
Python深入学习之特殊方法与多范式
Aug 31 #Python
python中的reduce内建函数使用方法指南
Aug 31 #Python
Python中使用ConfigParser解析ini配置文件实例
Aug 30 #Python
python进阶教程之动态类型详解
Aug 30 #Python
python进阶教程之异常处理
Aug 30 #Python
python进阶教程之函数对象(函数也是对象)
Aug 30 #Python
python进阶教程之循环对象
Aug 30 #Python
You might like
Zend Framework常用校验器详解
2016/12/09 PHP
php实现留言板功能
2017/03/05 PHP
一个JS小玩意 几个属性相加不能超过一个特定值.
2009/09/29 Javascript
JSP跨iframe如何传递参数实现代码
2013/09/21 Javascript
JQuery Tips相关(1)----关于$.Ready()
2014/08/14 Javascript
SeaJS 与 RequireJS 的差异对比
2014/12/08 Javascript
JQuery实现鼠标移动图片显示描述层的方法
2015/06/25 Javascript
在javascript中随机数 math random如何生成指定范围数值的随机数
2015/10/21 Javascript
js获取上传文件的绝对路径实现方法
2016/08/02 Javascript
浅谈js中StringBuffer类的实现方法及使用
2016/09/02 Javascript
jquery插件bootstrapValidator数据验证详解
2016/11/09 Javascript
vue计算属性时v-for处理数组时遇到的一个bug问题
2018/01/21 Javascript
使用JavaScript解析URL的方法示例
2019/03/01 Javascript
[48:53]2014 DOTA2华西杯精英邀请赛 5 25 LGD VS VG第一场
2014/05/26 DOTA
Python查询Mysql时返回字典结构的代码
2012/06/18 Python
小结Python用fork来创建子进程注意事项
2014/07/03 Python
Python中音频处理库pydub的使用教程
2017/06/07 Python
一百行python代码将图片转成字符画
2021/02/19 Python
python 实现UTC时间加减的方法
2018/12/31 Python
TensorFlow实现打印每一层的输出
2020/01/21 Python
Pyecharts地图显示不完成问题解决方案
2020/05/11 Python
Python matplotlib可视化实例解析
2020/06/01 Python
keras实现基于孪生网络的图片相似度计算方式
2020/06/11 Python
django表单中的按钮获取数据的实例分析
2020/07/31 Python
Pytho爬虫中Requests设置请求头Headers的方法
2020/09/22 Python
Python爬虫定时计划任务的几种常见方法(推荐)
2021/01/15 Python
Expedia挪威官网:酒店、机票和租车
2018/03/03 全球购物
VC++笔试题
2014/10/13 面试题
商务助理岗位职责
2013/11/13 职场文书
测试工程师岗位职责
2013/11/28 职场文书
乡镇组织委员个人整改措施
2014/09/16 职场文书
群众路线班子对照检查材料
2014/09/25 职场文书
单身证明格式样本
2015/06/15 职场文书
完美处理python与anaconda环境变量的冲突问题
2021/04/07 Python
再次探讨go实现无限 buffer 的 channel方法
2021/06/13 Golang
Mysql如何实现不存在则插入,存在则更新
2022/03/25 MySQL