设为首页 加入收藏

TOP

Python上下文管理器
2015-07-16 12:54:53 来源: 作者: 【 】 浏览:5
Tags:Python 上下文 管理

在使用Python编程中,可以会经常碰到这种情况:有一个特殊的语句块,在执行这个语句块之前需要先执行一些准备动作;当语句块执行完成后,需要继续执行一些收尾动作。


例如:当需要操作文件或数据库的时候,首先需要获取文件句柄或者数据库连接对象,当执行完相应的操作后,需要执行释放文件句柄或者关闭数据库连接的动作。


又如,当多线程程序需要访问临界资源的时候,线程首先需要获取互斥锁,当执行完成并准备退出临界区的时候,需要释放互斥锁。


对于这些情况,Python中提供了上下文管理器(Context Manager)的概念,可以通过上下文管理器来定义/控制代码块执行前的准备动作,以及执行后的收尾动作。


那么在Python中怎么实现一个上下文管理器呢?这里,又要提到两个"魔术方法",__enter__和__exit__,下面就是关于这两个方法的具体介绍。


也就是说,当我们需要创建一个上下文管理器类型的时候,就需要实现__enter__和__exit__方法,这对方法就称为上下文管理协议(Context Manager Protocol),定义了一种运行时上下文环境。


在Python中,可以通过with语句来方便的使用上下文管理器,with语句可以在代码块运行前进入一个运行时上下文(执行__enter__方法),并在代码块结束后退出该上下文(执行__exit__方法)。


with语句的语法如下:


在Python的内置类型中,很多类型都是支持上下文管理协议的,例如file,thread.LockType,threading.Lock等等。这里我们就以file类型为例,看看with语句的使用。


当需要写一个文件的时候,一般都会通过下面的方式。代码中使用了try-finally语句块,即使出现异常,也能保证关闭文件句柄。


其实,Python的内置file类型是支持上下文管理协议的,可以直接通过内建函数dir()来查看file支持的方法和属性:


所以,可以通过with语句来简化上面的代码,代码的效果是一样的,但是使用with语句的代码更加的简洁:


对于自定义的类型,可以通过实现__enter__和__exit__方法来实现上下文管理器。


看下面的代码,代码中定义了一个MyTimer类型,这个上下文管理器可以实现代码块的计时功能:


下面结合with语句使用这个上下文管理器:


代码输出结果为:



在使用上下文管理器中,如果代码块 (with_suite)产生了异常,__exit__方法将被调用,而__exit__方法又会有不同的异常处理方式。


当__exit__方法退出当前运行时上下文时,会并返回一个布尔值,该布尔值表明了"如果代码块 (with_suite)执行中产生了异常,该异常是否须要被忽略"。


1. __exit__返回False,重新抛出(re-raised)异常到上层


修改前面的例子,在MyTimer类型中加入了一个参数"ignoreException"来表示上下文管理器是否会忽略代码块 (with_suite)中产生的异常。


运行这段代码,会得到以下结果,由于__exit__方法返回False,所以代码块 (with_suite)中的异常会被继续抛到上层代码。



2. __exit__返回Ture,代码块 (with_suite)中的异常被忽略


将代码改为__exit__返回为True的情况:


运行结果就变成下面的情况,代码块 (with_suite)中的异常被忽略了,代码继续运行:



一定要小心使用__exit__返回Ture的情况,除非很清楚为什么这么做。


3. 通过__exit__函数完整的签名获取更多异常信息


对于__exit__函数,它的完整签名如下,也就是说通过这个函数可以获得更多异常相关的信息。


继续修改上面例子中的__exit__函数如下:


这次运行结果中,就显示出了更多异常相关的信息了:



本文介绍了Python中的上下文管理器,以及如何结合with语句来使用上下文管理器。


总结一下with 语句的执行流程:


在很多情况下,with语句可以简化代码,并增加代码的健壮性。


】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇Python中的and/or 下一篇Node.js表单——formidable

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: