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 14 Python
python学习之面向对象【入门初级篇】
Jan 21 Python
TensorFlow 滑动平均的示例代码
Jun 19 Python
面向初学者的Python编辑器Mu
Oct 08 Python
Python编程中flask的简介与简单使用
Dec 28 Python
Python实现求两个数组交集的方法示例
Feb 23 Python
使用Python在Windows下获取USB PID&VID的方法
Jul 02 Python
Python爬虫:url中带字典列表参数的编码转换方法
Aug 21 Python
IDLE下Python文件编辑和运行操作
Apr 25 Python
Python函数参数分类原理详解
May 28 Python
python super()函数的基本使用
Sep 10 Python
Python WebSocket长连接心跳与短连接的示例
Nov 24 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
php查看session内容的函数
2008/08/27 PHP
zend Framework中的Layout(模块化得布局)详解
2013/06/28 PHP
浅谈PHP变量作用域以及地址引用问题
2013/12/27 PHP
PHP中的按位与和按位或操作示例
2014/01/27 PHP
详解Yii2 之 生成 URL 的方法
2017/06/16 PHP
PHP的new static和new self的区别与使用
2019/11/27 PHP
jquery中获取元素的几种方式小结
2011/07/05 Javascript
javascript中的void运算符语法及使用介绍
2013/03/10 Javascript
js动态设置鼠标事件示例代码
2013/10/30 Javascript
ECharts仪表盘实例代码(附源码下载)
2016/02/18 Javascript
谈谈Vue.js——vue-resource全攻略
2017/01/16 Javascript
layui table设置前台过滤转义等方法
2018/08/17 Javascript
Vue中使用better-scroll实现轮播图组件
2020/03/07 Javascript
[05:08]2014DOTA2国际邀请赛 Hao专访复仇的胜利很爽
2014/07/15 DOTA
[04:02]DOTA2上海特锦赛小组赛第二日recap精彩回顾
2016/02/28 DOTA
python将多个文本文件合并为一个文本的代码(便于搜索)
2011/03/13 Python
Python实现从脚本里运行scrapy的方法
2015/04/07 Python
python复制文件的方法实例详解
2015/05/22 Python
Python实现统计英文单词个数及字符串分割代码
2015/05/28 Python
Python连接PostgreSQL数据库的方法
2016/11/28 Python
python编程实现随机生成多个椭圆实例代码
2018/01/03 Python
python编程测试电脑开启最大线程数实例代码
2018/02/09 Python
Python实现的基于优先等级分配糖果问题算法示例
2018/04/25 Python
python装饰器简介---这一篇也许就够了(推荐)
2019/04/01 Python
Python安装Flask环境及简单应用示例
2019/05/03 Python
Python中PyQt5/PySide2的按钮控件使用实例
2019/08/17 Python
Python版中国省市经纬度
2020/02/11 Python
关于Django Models CharField 参数说明
2020/03/31 Python
CSS3实现简易版的刮刮乐效果
2016/09/27 HTML / CSS
ShellScript面试题一则-ShellScript编程
2014/06/24 面试题
办公室文员工作自我评价
2013/12/01 职场文书
奥利奥广告词
2014/03/20 职场文书
毕业答辩开场白范文
2015/05/27 职场文书
提档介绍信范文
2015/10/22 职场文书
vue使用节流函数的踩坑实例指南
2021/05/20 Vue.js
嵌入式Redis服务器在Spring Boot测试中的使用教程
2021/07/21 Redis