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

上下文管理器

在使用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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/558244.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android日志[基础篇]Android Log日志输出

Android日志[基础篇]二 Android Studio修改LogCat日志的颜色 android.util.Log输出日志的常用方法如下: Log.v(String tag, String msg)Log.d(String tag, String msg)Log.i(String tag, String msg)Log.w(String tag, String msg)Log.e(String tag, String msg) …

python函数应用_python 函数应用

#函数的参数就是个变量#定义函数的时候,使用关键字参数,可以指定默认值def hello(namereboot,age1):return hello %s,your age is %s %(name,age)print hello(reboot,3)print hello(3,reboot)#print hello(age3,namereboot)print hello(reboot)def f(n):…

Android日志[基础篇]二 Android Studio修改LogCat日志的颜色

上一篇提到Android日志的5个级别的日志输出,在logcat里面设置自己喜欢或习惯的颜色,本文不只讲Android Sudio修改logcat的日志颜色。 代码和效果 代码 private void logColor(){Log.v(TAG,"logColor verbose");Log.d(TAG,"logColor de…

readfile函数使用方法_1分钟学会LOOKUP函数,有网友说使用这个方法,初学者秒变大神...

Hi,大家好,本专栏将会从零开始和大家用图文的方式,30天让你从不会到熟练使用函数,0基础开始学习Excel函数,让你喜欢上它!有兴趣的小伙伴可以持续关注我,或者在专栏进行查看学习,愿与…

Android JNI Attempt to remove non-JNI local reference, dumping thread

Attempt to remove non-JNI local reference, dumping thread 解决办法: 去除Jni代码 env->DeleteLocalRef(javaObject);注意:是java层传递给jni层的对象不需用了DeleteLocalRef来进行对象删除,jni层创建的对象仍然需要保留代码。 这个…

背景图层和普通图层的区别_图层样式(一)—高级混合选项

一、图层顺序为了便于说明,首先建立例子,新建图层,用画笔随便画个圈,新建蒙版随便画一笔,然后把所有图层样式加给它。可以看到样式从上到下的顺序,这也是它们混合的图层顺序。图层顺序我的效果,…

Android9.0 http网络请求失败问题的处理

目录处理方法(任意一种):APP改用https请求targetSdkVersion 降到27以下配置network-security-config(推荐)原因出错案例处理方法(任意一种): APP改用https请求 这种方式是最佳方法,需要前后端协调,后端得…

代码里无图片地址_项目实战:爬高清图片

↑ 关注 星标 ,后台回复【大礼包】送你2TPython自学资料好消息:Python学习交流群,已经建立,猛戳加入之前我发过一些爬虫的文章,不过一直没发过爬取图片的,今天就给大家分享一篇吧!/1 前言/上篇…

Android TextView通过SpannableString设置字体、大小、颜色、样式、超级链接

代码应该都能看明白 public class MainActivity extends ActionBarActivity {private TextView tv, tv2;private SpannableString sStr, sStr2;Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.act…

winform项目_winform项目——仿QQ即时通讯程序01:原理及项目分析

即时通讯程序,腾讯QQ可以说是一家独大,虽然市场上仍然有类似QQ的即时通讯程序,但是基本上面向的对象都是特定人群。那么,现在做一个即时通讯的软件还有意义吗?在我看来,意义非常大。作为一个学习编程的人&a…

Android面试基础一

Android面试基础二-原理及常见问题 目录1、四大组件1)Activity2)Service3)ContentProvider4)Broadcast Receiver2、四大组件的生命周期和简单用法1)Activity2)Service3)BroadcastReceiver4&…

python怎么用大数据分析师_如何七周成为数据分析师18:Python的新手教程

本文是《怎样七周成为数据剖析师》的第十八篇教程,假定想要了解写作初衷,能够先行阅读七周指南。温馨提示:假定您曾经熟习Python,大可不用再看这篇文章,或只选择部分。Python是近年来最火爆的言语,曾经作为…

Android面试基础二-原理及常见问题

Android 面试基础一 目录Android源码相关分析1、Android属性动画实现原理2、补间动画实现原理3、Android各个版本API的区别4、Requestlayout,onlayout,onDraw,DrawChild区别与联系5、invalidate和postInvalidate的区别及使用6、Activity-Wind…

python数据展示库_收藏!盘点很实用的数据科学Python库

数据科学是一门研究数据并从中挖掘信息的学科。它不要求自创或学习新的算法,只需要知道怎么样研究数据并解决问题。这一过程的关键点之一就在于使用合适的库。本文概述了数据科学中常用的、并且有一定重要性的库。在进入正题之前,本文先介绍了解决数据科…

Android日志[进阶篇]二-分析堆栈轨迹(调试和外部堆栈)

Android日志[进阶篇]一-使用 Logcat 写入和查看日志 Android日志[进阶篇]二-分析堆栈轨迹(调试和外部堆栈) Android日志[进阶篇]三-Logcat命令行工具 Android日志[进阶篇]四-获取错误报告 Android日志[进阶篇]五-阅读错误报告 目录调试中的堆栈轨迹从外部来源打开堆栈轨迹监控剪…

python股票数据分析实验报告_Python实验报告

一、实验原理(要求、任务等)(一)、Python的开发环境Python诞生于20世纪90年代初,是一种解释型、面向对象、动态数据类型的高级程序设计语言,是最受欢迎的程序设计语言之一。编写、编译和运行Python程序有以下3种方法。1.使用交互式解释器2.使用Windows命…

Android日志[进阶篇]一-使用 Logcat 写入和查看日志

Android日志[进阶篇]一-使用 Logcat 写入和查看日志 Android日志[进阶篇]二-分析堆栈轨迹(调试和外部堆栈) Android日志[进阶篇]三-Logcat命令行工具 Android日志[进阶篇]四-获取错误报告 Android日志[进阶篇]五-阅读错误报告 目录查看应用日志写入日志消息Logcat 消息格式设置…

哈希表数据结构_算法与数据结构-哈希表

前面我们已经讲到了数组和链表,数组能通过下标 O(1) 访问,但是删除一个中间元素却要移动其他元素,时间 O(n)。 循环双端链表倒是可以在知道一个节点的情况下迅速删除它,但是吧查找又成了 O(n)。难道就没有一种方法可以快速定位和删…

Android日志[进阶篇]三-Logcat 命令行工具

Android日志[进阶篇]一-使用 Logcat 写入和查看日志 Android日志[进阶篇]二-分析堆栈轨迹(调试和外部堆栈) Android日志[进阶篇]三-Logcat命令行工具 Android日志[进阶篇]四-获取错误报告 Android日志[进阶篇]五-阅读错误报告 目录日志记录系统概览命令行语法logcat命令行选项过…

python while语法结构_python语法之流程控制(if while for)

一.python语法之流程控制1.1什么是流程控制?流程控制即控制流程,具体指控制程序的执行流程,而程序的执行流程分为三种结构:顺序结构(之前我们写的代码都是顺序结构)、分支结构(判断)、循环结构(while for)二.分支结构2.1 什么是分…