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的框架下的web app的详细教程
Apr 30 Python
Python使用爬虫猜密码
Feb 19 Python
Python优先队列实现方法示例
Sep 21 Python
用Python实现KNN分类算法
Dec 22 Python
pycharm的console输入实现换行的方法
Jan 16 Python
浅谈python3.6的tkinter运行问题
Feb 22 Python
Pandas之MultiIndex对象的示例详解
Jun 25 Python
Python如何筛选序列中的元素的方法实现
Jul 15 Python
python运用pygame库实现双人弹球小游戏
Nov 25 Python
Pytorch之保存读取模型实例
Dec 30 Python
使用wxpy实现自动发送微信消息功能
Feb 28 Python
Pandas 数据编码的十种方法
Apr 20 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动态实现表格跨行跨列实现代码
2012/11/06 PHP
php笔记之:AOP的应用
2013/04/24 PHP
PHP获取当前日期和时间及格式化方法参数
2015/05/11 PHP
PHP的Json中文处理解决方案
2016/09/29 PHP
php利用嵌套数组拼接与解析json的方法
2017/02/07 PHP
如何在centos8自定义目录安装php7.3
2019/11/28 PHP
JavaScript Chart 插件整理
2010/06/18 Javascript
JavaScript中的ubound函数使用实例
2014/11/04 Javascript
原生js和jquery实现图片轮播特效
2015/04/23 Javascript
JavaScript中使用concat()方法拼接字符串的教程
2015/06/06 Javascript
不得不分享的JavaScript常用方法函数集(下)
2015/12/25 Javascript
限制只能输入数字的实现代码
2016/05/16 Javascript
js获取当前时间(昨天、今天、明天)
2016/11/23 Javascript
Bootstrap基本样式学习笔记之表格(2)
2016/12/07 Javascript
JavaScript中的this陷阱的最全收集并整理(没有之一)
2017/02/21 Javascript
jquery平滑滚动到顶部插件使用详解
2017/05/08 jQuery
解决webpack -p压缩打包react报语法错误的方法
2017/07/03 Javascript
Router解决跨模块下的页面跳转示例
2018/01/11 Javascript
基于mpvue小程序使用echarts画折线图的方法示例
2019/04/24 Javascript
vxe-table vue table 表格组件功能
2019/05/26 Javascript
node基于async/await对mysql进行封装
2019/06/20 Javascript
vue+element实现图片上传及裁剪功能
2020/06/29 Javascript
Django小白教程之Django用户注册与登录
2016/04/22 Python
python SSH模块登录,远程机执行shell命令实例解析
2018/01/12 Python
Python csv文件的读写操作实例详解
2019/11/19 Python
基于python及pytorch中乘法的使用详解
2019/12/27 Python
PyQt5.6+pycharm配置以及pyinstaller生成exe(小白教程)
2020/06/02 Python
Python word文本自动化操作实现方法解析
2020/11/05 Python
WoolOvers爱尔兰:羊绒、羊毛和棉针织品
2017/01/04 全球购物
SQL Server笔试题
2012/01/10 面试题
大学生职业生涯规划方案
2014/01/03 职场文书
绿色环保口号
2014/06/12 职场文书
2015年个人审计工作总结
2015/04/07 职场文书
2016新年致辞
2015/08/01 职场文书
浅谈Golang 嵌套 interface 的赋值问题
2021/04/29 Golang
Django程序的优化技巧
2021/04/29 Python