[Python] 关于 with 你所不知道的事

相信用 C 语言写过档案读取的人都知道,经常开档后就忘记关档,或者程式中间跳出例外,因此没有关档。这些问题常常让人非常头痛?。

所幸 Python 中有 with 这个语法糖,可以自动帮你开关档,跳出例外也难不倒他,真的非常好用。

但你真的了解 with 背后的运行原理吗? ?

不知道没关係,因为你现在就会知道了!

context manager

在讲 with 之前,必须先介绍一下 context manager,中文可以翻成 情境管理器。

为什么叫做 情境管理器 呢? 我们试想一个情境...

当你进入房间时,就要开启房间的灯:然后当你离开房间时,就要关闭房间的灯。

像这样理所当然一定要做的事情,我们就称为一个情境。而 Python 就是透过情境管理器处理这些情境。

要自己实作 context manager 其实很简单,只要在 Class 中实作 __enter__()__exit__() 即可。

就以进入房间当作例子。

class Room():    def turn_on_light(self):        print("开灯")    def turn_off_light(self):        print("关灯")    def __enter__(self):        print("进入房间")        self.turn_on_light()        return "在房间里"    def __exit__(self, exc_type, exc_value, traceback):        self.turn_off_light()        print("离开房间")with Room() as room:    print(room)

执行之后会印出以下结果:

进入房间开灯在房间里关灯离开房间

这非常的直觉,当我们宣告 with Room() 时,就会自动去呼叫 Room() 里面的 __enter__() 这个函数。后面的 room 就是回传的字串 "在房间里" 哦!

当程式离开 with 的範围时,就会自动去呼叫 __exit__() 这个函数。这多了三个参数分别是 exc_type (例外型态), exc_value (例外值), traceback (错误追蹤结果),下一个例子示範如何使用这三个参数。

class Room():    def turn_on_light(self):        print("开灯")    def turn_off_light(self):        print("关灯")    def __enter__(self):        print("进入房间")        self.turn_on_light()        return "在房间里"    def __exit__(self, exc_type, exc_value, traceback):        if not exc_type:            self.turn_off_light()            print("离开房间")        else:            print("Exception type:", exc_type)            print("Exception value:", exc_value)            print("Traceback:", traceback)with Room() as room:    print(i)    # NameError

执行结果:

进入房间开灯Exception type: <class 'NameError'>Exception value: name 'i' is not definedTraceback: <traceback object at 0x0000023862DD4700>Traceback (most recent call last):  File "D:\Andy\Code\test_with\test02.py", line 26, in <module>    print(i)NameError: name 'i' is not defined. Did you mean: 'id'?

我故意使用一个没宣告过的变数,让程式跳出 NameError,然后就会直接呼叫 __exit__(),并传入错误讯息的参数。如果正常没出错的情况,exc_type 会是 None,就会去执行原本的程式 (关灯)。

所以 Python 常用的 open() 实际上就是一个 context manager,__enter__() 就写开档相关的程式,__exit__() 则写关档相关的程式,就完成啦!

偶尔去研究一下 Python 一些语法的实作也满有趣的呢?

参考资料

Python 浅谈 with 语句Python 的 with 语法使用教学:Context Manager 资源管理器

关于作者: 网站小编

码农网专注IT技术教程资源分享平台,学习资源下载网站,58码农网包含计算机技术、网站程序源码下载、编程技术论坛、互联网资源下载等产品服务,提供原创、优质、完整内容的专业码农交流分享平台。

热门文章