承上启下继往开来,Python3上下文管理器(ContextManagers)与With关键字的迷思

在开发过程中,我们会经常面临的一个常见问题是如何正确管理外部资源,比如数据库、锁或者网络连接。稍不留意,程序将永久保留这些资源,即使我们不再需要它们。此类问题被称之为内存泄漏,因为每次在不关闭现有资源的情况下创建和打开给定资源的新实例时,可用内存都会减少。

正确管理资源往往是一个棘手的问题,因为资源的使用往往需要进行善后工作。善后工作要求执行一些清理操作,例如关闭数据库、释放锁或关闭网络连接。如果忘记执行这些清理操作,就可能会浪费宝贵的系统资源,例如内存和网络带宽。

背景

譬如,当开发人员使用数据库时,可能会出现一个常见问题是程序不断创建新连接而不释放或重用它们。在这种情况下,数据库后端可以停止接受新连接。这可能需要管理员登录并手动终止这些陈旧的连接,以使数据库再次可用。

以著名的ORM工具Peewee为例子:

当我们声明数据库实例之后,试图链接数据库:

程序输出:

但如果重复的创建链接:

就会抛出异常:

所以,需要手动关闭数据库链接:

返回:

但这样操作有一个潜在的问题,如果在调用connect的过程中,出现了异常进而导致后续代码无法继续执行,close方法无法被正常调用,因此数据库资源就会一直被该程序占用而无法被释放。

继续改进:

改进后的逻辑是对可能发生异常的代码处进行OperationalError异常捕获,使用 try/finally 语句,该语句表示如果在 try 代码块中程序出现了异常,后续代码就不再执行,而直接跳转到 except 代码块。而最终,finally块逻辑的代码被执行。因此,只要把 close方法放在 finally 代码块中,数据库链接就会被关闭。

事实上,Peewee为我们提供了一种更加简洁、优雅的方式来操作数据库链接:

也就是使用with 关键字来进行操作,这里使用with开启数据库的上下文管理器,当程序离开with关键字的作用域时,系统会自动调用close方法,最终效果和上文的捕获OperationalError异常一致,系统会自动关闭数据库链接。

上下文管理器(ContextManagers)

那么Peewee底层是如何实现对数据库的自动关闭呢?那就是使用Python3内置的上下文管理器,在Python中,任何实现了 __enter__() 和 __exit__() 方法的对象都可称之为上下文管理器,上下文管理器对象可以使用 with 关键字:

__enter__() 方法负责打开数据库链接,__exit__() 方法负责处理一些善后工作,也就是关闭数据库链接。

藉此,我们就可以使用with关键字对Db这个类对象进行调用了:

程序返回:

如此,我们就无需显性地调用 close方法了,由系统自动去调用,哪怕中间抛出异常 close方法理论上也会被调用。

上下文语法糖

Python3 还提供了一个基于上下文管理器的装饰器,更进一步简化了上下文管理器的实现方式。通过 生成器yield关键字将方法分割成两部分,yield 之前的语句在 __enter__ 方法中执行,yield 之后的语句在 __exit__ 方法中执行。紧跟在 yield 后面的值是函数的返回值:

随后通过with关键字调用contextmanager装饰后的方法:

与此同时,Peewee也贴心地帮我们将此装饰器封装了起来:

看起来还不错。

迷思:上下文管理一定可以善后吗?

请别太笃定,是的,上下文管理器美则美矣,但却未尽善焉,在一些极端情况下,未必能够善后:

程序返回:

当我们通过with关键字调用上下文管理器时,在__enter__方法内通过exit()方法强行关闭程序,过程中程序会立刻结束,并未进入到__exit__方法中执行关闭流程,也就是说,这个数据库链接并未被正确关闭。

同理,当我们书写了finally关键字,理所当然的,finally代码块理论上一定会执行,但其实,也仅仅是理论上:

程序返回:

显而易见,当程序进入finally代码块之前,就立刻触发了一个生成器generator异常,当理论上要被捕获异常时程序被yield返回了原始状态,于是立刻退出,放弃了执行finally逻辑。

所以,逻辑上,我们并不能指望上下文管理器每一次都能够帮我们“善后”,至少,在事情尚未收束的情况下,能够随机应变:

结语

使用With关键字操作上下文管理器可以更快捷地管理外部资源,同时能提高代码的健壮性和可读性,但在极端情况下,上下文管理器也并非万能,还是需要诸如轮询服务等托底保障方案。

最新资讯

文档百科

男性早期图片尖湿锐尤能治好吗

男性尖锐湿疣的症状主要表现为生殖器上乳头状或菜花状或鸡肉冠状肉的生长。男性早期尖湿锐尤能治好吗根据您的问题,尖锐湿疣是由人乳头瘤病毒感染引起的性传播疾病。通常,尖锐湿疣可以通过标准治疗,随访和随访诊断后治愈。此外,尖锐湿疣也可发生在肛门周围或直肠中。尖锐湿疣的主要发病率在温暖和潮湿的地区,发生在有性活动的中青年。

诺雷得价格多少钱一支

现在患者购买药物时对价格都非常关注,比如诺雷得药物,这种药物有进口与国产之分,自然在价格上存在一定差异。那么,诺雷得价格多少钱一支呢?据相关文献显示,国产诺雷得最低价格也需1800元才能买到一盒。诺雷得价格虽贵,但好在该药物属于医保范围内的药物,可以用医保进行报销。

鄂尔多斯羊绒裤暖和吗?鄂尔多斯羊绒裤是真的吗?

鄂尔多斯的羊绒裤相信很多人都在广告里面看到过,一直是她家的明星产品了,非常受欢迎。下面5号网小编给大家讲讲鄂尔多斯羊绒裤暖和吗?鄂尔多斯羊绒裤暖和吗鄂尔多斯家的羊绒裤非常暖和,可能很多人还没接触过羊绒裤,但是穿过羊绒衫的肯定不在少数,羊绒裤比羊绒衫的保暖性要更加好,怕冷的朋友赶紧入手吧!

夏天种什么花好养活?这个季节生长最旺盛的茉莉花

夏天种花最好是选择当季的花朵,比如茉莉花、三角梅、石竹、碗莲以及矮牵牛等,其中茉莉花在夏季是生长最旺盛的时候,不管是已经成型的,还是幼苗,都可以放心的在夏季养殖,成活率都是非常高的,不过要分清茉莉花和栀子花的区别,其次就是三角梅,只要提供相对通风的环境,那么高温就不成问题,也能很好的养活。

运动减肥的3大饮食误区

下面小编就介绍一下运动减肥的3大饮食误区有哪些。空腹运动减脂更快?平时也要多了解女性减肥期间应避开哪些饮食误区等相关常识,毕竟科学的食疗方法才能健康有效减肥。

温州有儿童室内攀岩的场所吗

目前在一些体育中心、军警训练基地以及一些特种部队中也开展了这种攀岩训练,下面跟着老资料网小编来了解一下温州有儿童室内攀岩的场所吗?当然有了,温州市鹿城区花源路东瓯智库58号1楼有攀岩馆,在小茶悦会后面。岩馆有国家级攀岩教练员2名,国家级攀岩定线员1名,能确保对市民的攀岩运动进行专业的指导。

CopyRight © 2000~2023 一和一学习网 Inc.All Rights Reserved.
一和一学习网:让父母和孩子一起爱上学习