Python with
with 语句用于包装带有使用上下文管理器定义的方法的代码块的执行
可以用来替代 try
语句
执行过程
- 对上下文表达式求值,获得一个上下文管理器
- 载入上下文管理器的
__exit__()
- 发起调用上下文管理器的
__enter__()
方法 - 如果
with
语句包含一个目标,来自__enter__()
的返回值将被赋予它 - 执行语句
- 调用
__exit__()
,如果执行语句时出现异常:将异常的类型、值、回溯信息传给__exit__()
;如果没有异常:传入 None
替代 try
语句
以打开文件为例:
try
语句:
f = open("text.txt", "r")
try:
print(f.read())
except Exception:
print("error occurred")
finally:
f.close()
with
语句:
with open("text.txt", "r") as f:
print(f.read())
上下文管理器 (context managers)
上下文管理器属于上下文管理器类型 (Context Manager Types),用于 with
语句定义运行上下文
有 __enter__()
和 __exit__()
的对象都可以是上下文管理器
方法
contextmanager.__enter__()
以 with open() as f:
为例:文件对象会从 __enter__()
返回自身,使得 open()
可以被用作上下文表达式 (context expression)
contextmanager.__exit__(exc_type, exc_val, exc_tb)
返回 True
时表示屏蔽异常,会继续执行 with
之后的语句;返回 False
时异常会在此方法执行结束后继续传播
自定义上下文管理器
实现打开文件的功能:
class UserContextManager(object):
def __init__(self, file_name, mode):
self.file_name = file_name
self.mode = mode
def __enter__(self):
self.f = open(self.file_name, self.mode)
return self.f
def __exit__(self, exc_type, exc_val, exc_tb):
self.f.close()
with UserContextManager("text.txt", "r") as f:
print(f.read())
contextlib
Python 标准库中的 contextlib 包含许多支持 with 语句的程序
官方文档:https://docs.python.org/zh-cn/3/library/contextlib.html#module-contextlib
contextmanager
contextmanager
可以通过一个装饰器,实现 with
语句的功能
yield
之前的语句在 __enter__()
中执行,yield
之后的语句在 __exit__()
中执行,yield
的为 __enter__()
的返回值
from contextlib import contextmanager
@contextmanager
def user_open(path, mode):
f = open(path, mode)
yield f
f.close()
with user_open('text.txt', 'r') as f:
print(f.read())