上下文管理器(Context managers)让我们在需要的时候可以准确地分配或释放资源
Python中最常用的上下文管理例子就是with语句了,一般是在操作文件的时候,比如:
有PY基础的小伙伴都知道,上面的代码等价于:
对比两个例子,可以看出前者更加优雅简洁,少了一些例行代码
with语句的好处就是:它确保我们的文件对象最终能被关闭掉
上下文管理器常用于锁定(locking)、解锁(unlocking)资源 或 关闭开启的文件(如上例子)
with语句用得多了,就会习惯了,可能不会去追究它的底层是怎样实现的(比如up就是了),这是不好的习惯
下面介绍下,如何实现一个我们自己的上下文管理器,带你揭开它的神秘面纱~
__enter__与__exit__ 魔术方法
下面我们自定义一个文件类,并实现__enter__与__exit__实例方法,那这个类就是一个上下文管理器了,可以与with语句配合使用:
执行结果:
所以流程是:
1遇上with语句时,__enter__方法先被执行,并返回一个变量
2返回的变量赋值给as的变量
3执行with语句块
4最后执行__exit__方法
其实上面这个代码只是脱裤子放屁,因为open函数返回的对象也实现了__enter__与__exit__方法:
注意到__enter__的返回值就是f本身
在__exit__方法中处理异常
细心的小伙伴可能注意到了,__exit__方法中有type、value、traceback参数,它们是干嘛用的?
事实上,当with语句块中出现异常时,上述三个参数会传递给__exit__方法,然后可以由我们决定,是否继续抛出异常
来看看无异常时,这三个参数是:
当出现异常时,这三个参数是:
type参数是异常对象所属的类
value参数是异常对象本身
traceback 即为一个从异常处理器到异常被抛出的点的栈追踪器
如果我们想忽略该异常并退出with语句块,只需要在__exit__函数返回一个True即可
可以看出在加上return True后,执行不再抛出异常,程序正常退出
用生成器语法实现一个上下文管理器
除了使用类实现外,Python有一个contexlib标准库,可以允许我们使用生成器函数来实现上下文管理器
只需要一些装饰器与生成器知识,来看基本的用法:
有兴趣的小伙伴可以自行研究下这个库