顾名思义,上下文管理器就是管理上下文的。实现代码块执行前准备,代码快执行后收拾。
应用场景:管理各种系统资源(文件、锁定、连接)时,如果出现异常比较棘手。异常会导致控制流跳过负责释放关键资源的语句。比如打开一个文件进行操作时发生意外(磁盘已满、特殊终端信号让其终止…),可能导致文件关闭操作无法执行,进而耗费系统资源。
之前采用try/finally
语句来解决此类问题,Python2.5之后加入上下文管理器处理此问题,增强代码可读性、减少错误。
with语句用于执行上下文操作,基本语法:
with context_expr [as var]:
with_suit
with语句只能工作于支持上下文管理协议(context management protocol)的对象。也就是说只有内建了”上下文管理”的对象才能和 with 一起工作。
Python内置了一些支持该协议的对象,如下所列是一个简短列表:
- file
- decimal.Context
- thread.LockType
- threading.Lock
- threading.RLock
- threading.Condition
- threading.Semaphore
- threading.BoundedSemaphore
file举例:
with open('pickle_symbols.pickle', 'rb') as f: # 打开文件,如果一切正常,读取数据赋值给df,之后关闭文件
df = pickle.load(f)
print(df)
无论是在这一段代码的开始,中间,还是结束时发生异常,会执行清理的代码,此 外文件仍会被自动的关闭。
前面提到with语句只能工作于支持上下文管理协议的对象,如果默认对象不能满足功能,就需要自己定义。核心就是下面两个方法:
__enter__()
:在使用with语句时调用,会话管理器在代码块开始前调用,返回值与as后的参数绑定
__exit__()
:会话管理器在代码块执行完成好后调用,在with语句完成时,对象销毁之前调用
with语句的执行流程
1. 执行 context_exp 以获取上下文管理器 2. 加载上下文管理器的 __exit__() 方法以备稍后调用 3. 调用上下文管理器的 __enter__() 方法 4. 如果有 as var 从句,则将 __enter__() 方法的返回值赋给 var 5. 执行子代码块 with_suit 6. 调用上下文管理器的 __exit__() 方法,如果 with_suit 的退出是由异常引发的,那么该异常的 type、value 和 traceback 会作为参数传给 __exit__(),否则传三个 None 7. 如果 with_suit 的退出由异常引发,并且 __exit__() 的返回值等于 False,那么这个异常将被重新引发一次;如果 __exit__() 的返回值等于 True,那么这个异常就被无视掉,继续执行后面的代码
contextlib模块可以提供更方便的上下午管理器。
- Object becomes None when using a context manager
- PEP 343 – The “with” Statement
- Understanding Python’s “with” statement
- The with command and custom classes
- Python with解析
__enter__()、__exit__()
(十五) - 浅谈 Python 的 with 语句
- Object becomes None when using a context manager
- Python深入02 上下文管理器
- 旷世的忧伤
- python
__enter__
与__exit__
的作用,以及与 with 语句的关系