Python中具备精确分配和释放资源功能的上下文管理器
创始人
2024-05-21 01:44:14
0

上下文管理器(Context managers)允许你在有需要的时候,精确地分配和释放资源。

with 语法

使用上下文管理器最广泛的案例就是with 语句了。 想象下你有两个需要结对执行的相关操作,然后还要在它们中间放置一段代码。 上下文管理器就是专门让你做这种事情的。 with的语法格式:

with context_expression [as target(s)]:with-body

举个使用了with的例子:

with open('some_file', 'w') as opened_file:opened_file.write('Hola!')

上面这段代码打开了一个文件,往里面写入了一些数据,然后关闭该文件。如果在往文件写数据时发生异常,它也会尝试去关闭文件。上面那段代码与这一段是等价的:

file = open('some_file', 'w')
try:file.write('Hola!')
finally:file.close()

当与第一个例子对比时,我们可以看到,通过使用with,许多样板代码被消掉了。 这就是with语句的主要优势,它确保我们的文件会被关闭,而不用关注嵌套代码如何退出。

上下文管理器的常见用例,是资源的加锁和解锁,以及关闭已打开的文件。

基于类的实现

with的语法非常简单,只需要 with一个表达式,就可以执行自定义的业务逻辑。但是with后面的表达式并不是可以任意写的。要想使用 with语法块,with后面的的对象需要实现上下文管理器协议。

一个类在 Python 中,只要实现以下方法,就实现了上下文管理器协议:

  • __enter__:在进入with语法块之前调用,返回值会赋值给 with的 target;

  • __exit__:在退出with语法块时调用,一般用作异常处理。

也就是说,一个上下文管理器的类,最起码要定义 __enter__ 和 __exit__ 方法。 接下来,我们来看一个构造自己的上下文管理器的例子:

class File(object):def __init__(self, file_name, method):self.file_obj = open(file_name, method)def __enter__(self):return self.file_objdef __exit__(self, type, value, traceback):self.file_obj.close()

通过定义__enter__ 和 __exit__ 方法,我们就可以在with语句里使用它。

with File('demo.txt', 'w') as opened_file:opened_file.write('Hola!')

首先,要知道的是__exit__函数接受三个参数。这些参数对于每个上下文管理器类中的 __exit__方法都是必须的。我们来谈谈在底层都发生了什么。

  1. with语句先暂存了File类的__exit__方法。

  1. 然后它调用 File 类的__enter__方法。

  1. __enter__方法打开文件并返回给 with语句。

  1. 打开的文件句柄被传递给 opened_file 参数。

  1. 我们使用.write()来写文件。

  1. with语句调用之前暂存的 __exit__ 方法。

  1. __exit__方法关闭了文件。

处理异常

接着,我们来谈谈__exit__方法的这三个参数:type,value和 traceback。 在第4步和第6步之间,如果发生异常,Python 会将异常的type,value和 traceback传递给 __exit__方法。 它让 __exit__方法来决定如何关闭文件以及是否需要其他步骤。

也就是说如果在 with语句块内发生了异常,那么 __exit__方法可以拿到关于异常的详细信息:

  • type:异常类型

  • value:异常对象

  • tb:异常堆栈信息

当异常发生时,with语句会采取如下步骤。

它把异常的type,value和 traceback传递给 __exit__方法。

它让 __exit__方法来处理异常。

如果 __exit__返回的是 True,那么这个异常就被优雅地处理了。

如果 __exit__返回的是 True以外的任何东西,那么这个异常将被 with语句抛出。

基于生成器的实现

对于需要上下文管理的场景,除了自己实现 __enter__ 和 __exit__ 之外,还可以更简单。我们可以使用 Python 标准库提供的contextlib模块,来简化我们的代码。

使用contextlib模块,我们可以把上下文管理器当成一个装饰器来使用。其中,contextlib模块提供了 contextmanager装饰器和closing方法。

来看一个简单的例子:

from contextlib import contextmanager@contextmanager
def test():print('before')yield 'hello'print('after')with test() as t:print(t)

在这个例子中,使用 contextmanager装饰器和yield配合,实现了和前文上下文管理器相同的功能,它的执行流程如下:

  1. 执行 test() 方法,先打印出 before

  1. 执行 yield 'hello',test方法返回,hello返回值会赋值给 with语句块的 t变量

  1. 执行 with语句块内的逻辑,打印出 t 的值 hello

  1. 又回到 test方法中,执行 yield后面的逻辑,打印出 after

这样一来,当我们使用这个 contextmanager装饰器后,就不用再写一个类来实现上下文管理协议,只需要用一个方法装饰对应的方法,就可以实现相同的功能。

不过有一点需要我们注意:在使用 contextmanager装饰器时,如果被装饰的方法内发生了异常,那么我们需要在自己的方法中进行异常处理,否则将不会执行 yield之后的逻辑。

我们再来看 contextlib提供的 closing方法如何使用。closing主要用在已经实现 close方法的资源对象上:

from contextlib import closingclass Test():def close(self):  # 定义了 close 方法才可以使用 closing 装饰器print('closed')# with 执行结束后 自动执行 close 方法
with closing(Test()):print('do something')

从执行结果我们可以看到,with语句块执行结束后,会自动调用 Test 实例的 close方法。所以,对于需要自定义关闭资源的场景,我们可以使用这个方法配合 with来完成。

总结

with非常适合用需要对于上下文处理的场景,例如操作文件、Socket,这些场景都需要在执行完业务逻辑后,释放资源。

相关内容

热门资讯

最绚丽的安卓系统,最绚丽版本全... 哇,你知道吗?在安卓的世界里,有一款系统,它就像是一颗璀璨的明珠,闪耀着最绚丽的色彩。它就是——最绚...
小米系统安卓通知权限,深度解析... 亲爱的手机控们,你是否曾为手机通知栏里乱糟糟的信息而烦恼?又或者,你是否好奇过,为什么有些应用总是能...
安卓7.0系统能玩吗,体验全新... 你有没有想过,你的安卓手机升级到7.0系统后,那些曾经陪伴你度过无数时光的游戏,还能不能继续畅玩呢?...
平板安卓系统哪家好,安卓平板系... 你有没有想过,在这个科技飞速发展的时代,拥有一台性能出色的平板电脑是多么重要的事情呢?想象无论是追剧...
安卓好的点歌系统,打造个性化音... 你有没有想过,在安卓手机上,点歌系统竟然也能如此精彩?没错,就是那个我们每天都会用到,却又常常忽略的...
熊猫安卓系统直播软件,解锁互动... 你知道吗?最近有个超级酷炫的直播软件在熊猫迷们中间火得一塌糊涂!它就是熊猫安卓系统直播软件。别看它名...
安卓点播系统开发,Androi... 你有没有想过,手机里那些让你爱不释手的视频,其实背后有着一套复杂的安卓点播系统在默默支撑呢?今天,就...
安卓6.0系统加权限,深度解析... 你有没有发现,自从手机升级到安卓6.0系统后,权限管理变得超级严格呢?这可真是让人又爱又恨啊!今天,...
哪些电视带安卓系统,多款热门智... 你有没有想过,家里的电视竟然也能装上安卓系统?听起来是不是有点不可思议?没错,现在市面上就有不少电视...
苹果怎么运用安卓系统,揭秘如何... 你知道吗?最近有个大新闻在科技圈里炸开了锅,那就是苹果竟然开始运用安卓系统了!是不是觉得有点不可思议...
安卓系统能转什么系统好,探索最... 你有没有想过,你的安卓手机是不是也能换换口味,体验一下其他系统的魅力呢?没错,今天就来聊聊这个话题:...
龙之狂热安卓系统,释放龙族狂热 亲爱的手机控们,你是否曾为拥有一款独特的安卓系统而疯狂?今天,就让我带你走进一个充满奇幻色彩的龙之狂...
vivo手机安卓系统怎么升级系... 亲爱的手机控们,你是不是也和我一样,对手机的新功能充满期待呢?尤其是vivo手机的用户,是不是也在想...
鸿蒙2.0退回安卓系统,一场系... 你知道吗?最近科技圈里可是炸开了锅,因为华为的鸿蒙2.0操作系统竟然要退回安卓系统了!这可不是一个简...
安卓系统怎么复制卡,安卓系统卡... 你有没有遇到过这种情况:手机里的照片、视频或者重要文件,突然想备份到电脑上,却发现安卓系统的卡复制功...
app兼容低安卓系统,打造全民... 你有没有发现,现在手机APP更新换代的速度简直就像坐上了火箭!不过,你知道吗?有些APP可是特别贴心...
中间安卓系统叫什么,中间安卓系... 你有没有想过,安卓系统里竟然还有一个中间的版本?没错,就是那个让很多手机用户既熟悉又陌生的版本。今天...
安卓怎么用os系统,利用And... 你有没有想过,你的安卓手机其实可以变身成一个功能强大的操作系统呢?没错,就是那个我们平时在电脑上使用...
pe系统安卓能做么,探索安卓平... 亲爱的读者,你是否曾好奇过,那款在安卓设备上大受欢迎的PE系统,它究竟能做什么呢?今天,就让我带你一...
安卓 打印机系统,安卓打印机系... 你有没有想过,家里的安卓手机和打印机之间竟然能建立起如此紧密的联系?没错,就是那个安卓打印机系统!今...