上下文管理器

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

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

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

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

上下文管理协议

那么在Python中怎么实现一个上下文管理器呢?这里,又要提到两个”魔术方法”,__enter__和__exit__,下面就是关于这两个方法的具体介绍。__enter__(self) Defines what the context manager should do at the beginning of the block created by the with statement. Note that the return value of __enter__ is bound to the target of the with statement, or the name after the as.

__exit__(self, exception_type, exception_value, traceback) Defines what the context manager should do after its block has been executed (or terminates). It can be used to handle exceptions, perform cleanup, or do something always done immediately after the action in the block. If the block executes successfully, exception_type, exception_value, and traceback will be None. Otherwise, you can choose to handle the exception or let the user handle it; if you want to handle it, make sure __exit__ returns True after all is said and done. If you don’t want the exception to be handled by the context manager, just let it happen.

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

with语句

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

with语句的语法如下:

Pythonwith context_expr [as var]:

with_suite

context_expr是支持上下文管理协议的对象,也就是上下文管理器对象,负责维护上下文环境

as var是一个可选部分,通过变量方式保存上下文管理器对象

with_suite就是需要放在上下文环境中执行的语句块

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

with语句简化文件操作

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

Pythonlogger = open("log.txt", "w")  try:

logger.write('Hello ')

logger.write('World')  finally:

logger.close()

print logger.closed

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

Python>>> print dir(file)

['__class__', '__delattr__', '__doc__', '__enter__', '__exit__', '__format__', '  __getattribute__', '__hash__', '__init__', '__iter__', '__new__', '__reduce__',  '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclass  hook__', 'close', 'closed', 'encoding', 'errors', 'fileno', 'flush', 'isatty', '  mode', 'name', 'newlines', 'next', 'read', 'readinto', 'readline', 'readlines',  'seek', 'softspace', 'tell', 'truncate', 'write', 'writelines', 'xreadlines']  >>>

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

Pythonwith open("log.txt", "w") as logger:

logger.write('Hello ')

logger.write('World')

print logger.closed

自定义上下文管理器

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

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

Pythonimport time

class MyTimer(object):

def __init__(self, verbose = False):

self.verbose = verbose

def __enter__(self):

self.start = time.time()

return self

def __exit__(self, *unused):

self.end = time.time()

self.secs = self.end - self.start

self.msecs = self.secs * 1000

if self.verbose:

print "elapsed time: %f ms" %self.msecs

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

Pythondef fib(n):

if n in [1, 2]:

return 1

else:

return fib(n-1) + fib(n-2)

with MyTimer(True):

print fib(30)

代码输出结果为:

异常处理和__exit__

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

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

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

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

Pythonimport time

class MyTimer(object):

def __init__(self, verbose = False, ignoreException = False):

self.verbose = verbose

self.ignoreException = ignoreException

def __enter__(self):

self.start = time.time()

return self

def __exit__(self, *unused):

self.end = time.time()

self.secs = self.end - self.start

self.msecs = self.secs * 1000

if self.verbose:

print "elapsed time: %f ms" %self.msecs

return self.ignoreException

try:

with MyTimer(True, False):

raise Exception("Ex4Test")

except Exception, e:

print "Exception (%s) was caught" %e  else:

print "No Exception happened"

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

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

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

Pythontry:

with MyTimer(True, True):

raise Exception("Ex4Test")

except Exception, e:

print "Exception (%s) was caught" %e  else:

print "No Exception happened"

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

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

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

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

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

Pythondef __exit__(self, exception_type, exception_value, traceback):

self.end = time.time()

self.secs = self.end - self.start

self.msecs = self.secs * 1000

if self.verbose:

print "elapsed time: %f ms" %self.msecs

print "exception_type: ", exception_type

print "exception_value: ", exception_value

print "traceback: ", traceback

return self.ignoreException

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

总结

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

总结一下with 语句的执行流程:执行context_expr 以获取上下文管理器对象

调用上下文管理器的 __enter__() 方法如果有 as var 从句,则将 __enter__() 方法的返回值赋给 var

执行代码块 with_suite

调用上下文管理器的 __exit__() 方法,如果 with_suite 产生异常,那么该异常的 type、value 和 traceback 会作为参数传给 __exit__(),否则传三个 None如果 with_suite 产生异常,并且 __exit__() 的返回值等于 False,那么这个异常将被重新抛出到上层

如果 with_suite 产生异常,兵器 __exit__() 的返回值等于 True,那么这个异常就被忽略,继续执行后面的代码

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

本文来自投稿,不代表访得立场,如若转载,请注明出处:http://www.found5.com//view/393.html

python语言使用什么语句实现上下文管理协议_Python 上下文管理器相关推荐

  1. python语言使用什么语句实现上下文管理协议_Python 技巧探究:上下文管理器和with语句...

    一:前言 Python 里面的 with 语句是被认为是晦涩难懂的特征之一,但是当你窥视它的内部你就会发现这里面并没有什么魔法.事实上它可以帮助我们写一些整洁和可读性高的代码. 那么 with 语句适 ...

  2. python语言使用什么语句实现上下文管理协议_Python with语句上下文管理器两种实现方法分析...

    本文实例讲述了Python with语句上下文管理器.分享给大家供大家参考,具体如下: 在编程中会经常碰到这种情况:有一个特殊的语句块,在执行这个语句块之前需要先执行一些准备动作:当语句块执行完成后, ...

  3. python语言的注释语句引导符不包括什么_以下选项中,哪一个是Python语言中代码注释使用的符号?________...

    [单选题]关于 Python 语句 P = –P,以下选项中描述正确的是________ [多选题]Python的数字类型包括( ) [多选题]Python中的注释符有哪几种?( ) [判断题]已知 ...

  4. python语言程序设计王恺答案在哪找_Python语言程序设计

    前言 第1章 初识Python 1 1.1 Python的基本概念 1 1.1.1 编译型语言与解释型语言 1 1.1.2 Python的发展史 3 1.1.3 Python的特点及应用领域 4 1. ...

  5. python内存管理方法_Python 内存管理大揭秘

    前言 语言的内存管理是语言设计的一个重要方面.它是决定语言性能的重要因素.无论是C语言的手工管理,还是Java的垃圾回收,都成为语言最重要的特征.这里以Python语言为例子,说明一门动态类型的.面向 ...

  6. 关于python语言和人工智能下哪个说法不正确_“在资源管理器”窗口中,文件夹图标左侧有“...

    [单选题]表示串行数据传输速率的指标为:___. [单选题]串行口工作在方式0时,其波特率:___. [简答题]发布混合碱含量的测定三个锥形瓶的滴定终点颜色 [简答题]将自己做的三个锥形瓶的滴定终点颜 ...

  7. python语言的多行注释以什么开头和结尾_Python单行注释与多行注释

    >>> print "hello,world" hello,world >>> 2+2 4 #单行注释 """每行 ...

  8. python语言保留字可以用变量名来命名_Python语言基本语法元素之变量,变量的含义及命名规则...

    教学是对知识的二次加工. 笔者希望给python初学者提供帮助.上一篇文章写了Python语言基本语法元素之格式框架:注释.缩进.续行符 这里继续,Python语言基本语法元素之变量. 我们来看看前4 ...

  9. python语言程序设计基础嵩天答案第二章_python语言程序设计基础(嵩天版),第二章程序练习题...

    python语言程序设计基础(嵩天版),第二章程序练习题 欢迎访问江南烧酒的博客 2.2汇率兑换程序.按照1美元=6人民币汇率编写一个美元和人民币的双向兑换程序. """ ...

最新文章

  1. IOS学习笔记(四)之UITextField和UITextView控件学习
  2. ETSI MEC — 参考架构模型
  3. 二叉树的前中后序递归和非递归遍历操作【代码】
  4. 【C++】 C++标准模板库(九) Bitsets
  5. 实现Windows和Linux之间的文件共享
  6. C/C++之函数返回值为指针或者是引用时常见错误总结
  7. java aop 实例_Spring aop 简单示例
  8. VS2015 vc++ 项目出现new.h找不到的错误
  9. javaSE学习 访问控制
  10. 你这几天因为 YYYY-MM-dd 被提 BUG 了吗??
  11. JavaWeb学习(二)Maven
  12. 面试必掌握的Mysql的11个问题
  13. 【免费】ArcGIS 10.8 软件下载及手把手安装教程(超详细)
  14. SpringBoot项目实现敏感词汇过滤
  15. forum.php 下载,PHPWind Forums
  16. unity3d + lua + 斗地主 系列 (2) 创建扑克规则
  17. win7 android双系统,真正的安卓Windows双系统,RemixOS Windows共存系统安装+附带RO......
  18. Opencv下双线性插值法进行图像放缩
  19. 理解“卷积” Understanding Convolutions
  20. Android传感器Motion Sensor开发实验

热门文章

  1. linkedhashset_Java LinkedHashSet clear()方法与示例
  2. c#equals方法源码_C#中的Int32.Equals()方法示例
  3. sql 数字减去null_减去两个16位数字| 8086微处理器
  4. 第 3-1 课:集合详解(上) + 面试题
  5. Redis都不懂?就别去面试了!聊聊我的Redis新专栏「视频版」
  6. jsp中redirect和forward的区别
  7. Stacked Hourglass Networks 人体姿态检测
  8. iterm2一键登陆服务器(门神权限不用每次都输密码进行验证)
  9. 怎么退出自适应巡航_简单聊聊定速巡航和自适应定速巡航的区别
  10. 简单mysql优化_mysql常见语句的简单优化策略