日记大全

日记大全 > 句子大全

Python的with语句实例(探讨上下文管理器的魔法方法及装饰器用法)

句子大全 2023-01-24 05:26:01
相关推荐

前面内容,我们详细探讨了Python中一些魔法方法的使用。

销毁之前,如何让对象发挥余热,Python魔法方法__del__()的使用

查看对象内部属性的名称和值,Python“魔法”属性__dict__的使用

需要帮助吗?dir函数的孪生兄弟,Python中魔法方法__dir__详解

你会给对象做一个简历吗?Python魔法方法__repr__()的应用详解

今天,我们通过一个简单的例子来探讨with和上下文管理器的原理和应用。

先来看一个简单的文件打开的例子:

f = open("123.txt", "w")

f.write("这是一个测试文件")

f.close()

程序执行后,目录下就生成了一个内容为“这是一个测试文件”,名为123.txt的文本文件。

前面的例子很简单,但是如果我们试图往文本文件中写入一个字典数据,结果会怎样呢?

运行程序,看下输出结果。

抛出异常后,程序有没有继续执行下面的f.close()呢?我们来看一下。

程序执行过程中,如果抛出异常,文件实例f没有被正确关闭。如果文件实例f占用内存很大呢?我们的系统就会不知不觉中变慢。这是个问题!

如何解决上面的问题呢?聪明的小伙伴肯定会想到这个方法:捕获异常并处理它们。我们来试试看。

其实,仔细想想,如果我们将之前生成的“123.txt”文件权限设置为只读,再运行上面这个程序,还是会抛出异常。

好吧,我们的程序还要改进。改成这样之后呢?

我们把程序改成了上面的样子,它可以捕获现有Python可知的异常。好吧,问题暂时解决了。

回归问题的本质,我们只是需要打开一个文件,然后往里面写入一些数据。为了这样的需求,我不仅要考虑程序中的异常问题,还要考虑文件流是否被正确关闭等等这些问题。

我们可以完美的解决异常和文件流的关闭问题。但是,我的本意是“打开和写入文件”。在解决异常和关闭文件流的过程中,我写了一堆与解决实质问题无关的代码,也耗费了一些本应节省的时间。

这与Python之禅相冲突。

有没有更好的方案解决呢?

with语句用于对资源进行访问的场合,比如,本例中的文件流。它还可以应用到数据库操作、网络传输等场合。它的应用可以确保不管程序运行过程中是否发生异常,都会对资源进行释放。with语句简化了我们的代码量。

我们来看下上面例子的with实现:

testDict = {"a": "b"}

with open("123.txt", "w") as f:

f.write(testDict)

可以实现清理f实例的功能。但是我们看到,在编译器中,当调用f时,它同样会打印结果。其实,f实例已经关闭了,这和编译器的清理机制有关。

我们再来对比一下不使用with的情况。如下图:

可以看到,不使用with语句,当出现异常时,f没有正确关闭,而使用with语句效果大不相同了。

讲到with语句,我们不得不提上下文管理器ContextManager。它是用来表示代码执行过程中所处的前后环境。我们前面也提到了魔法方法,上下文管理器中有__enter__ 和 __exit__两个方法,本质上来讲,可以使用with语句处理的地方,一般都是实现__enter__、__exit__两个魔法方法。

__enter__方法会在执行 with 后面的语句时执行,一般用来处理操作前的内容。比如一些创建对象,初始化等__exit__方法会在 with 内的代码执行完毕后执行,一般用来处理一些善后收尾工作,比如文件的关闭,数据库的关闭等。举个简单的例子:

这种方式很简单,你可以自定义一个使用with来处理的上下文管理器。

当然,还有一个更有意思的用法,那就是使用装饰器。这种方法进一步简化了上下文管理器的实现,它通过yield将函数分为两部分,yield之前的语句在__enter__()方法中执行,yield之后的语句在__exit__()执行。

怎么样?可以自定义了,然后代码又不是很多,但是可读性可能稍微差一点。

好了,今天的内容就到这里了,我们从一个例子开始,一起探讨了with语句、上下文管理器的相关用法。这个技能你get到了吗?

喜欢Python编程的小伙伴关注我,后续推出更加精彩的内容。

想了解更多精彩内容,快来关注python高手养成

转载请注明出处,百家号:Python高手养成

阅读剩余内容
网友评论
相关内容
拓展阅读
最近更新