什么是上下文管理器?
上下文管理器可以帮助使用资源(尽管可能会用于更多用途)。 context 基本上就是资源。
假设您打开了一个文件进行写入:
f = open(path, "w")
您现在有一个打开的文件句柄。在处理您的文件期间,没有其他程序可以写入它。为了让其他程序写入它,你必须关闭文件句柄:
f.close()
但是,在关闭您的文件之前发生了错误:
f = open(path, "w")
data = 3/0 # Tried dividing by zero. Raised ZeroDivisionError
f.write(data)
f.close()
现在将发生的情况是函数或整个程序将退出,同时让您的文件保持打开的句柄。 (CPython 在终止时清理句柄,并且句柄与程序一起释放,但您不应该指望这一点)
with 语句确保一旦你离开它的缩进,它就会关闭文件句柄:
with open(path, "w") as f:
data = 3/0 # Tried dividing by zero. Raised ZeroDivisionError
f.write(data)
# Here, the file is already closed automatically, no matter what happened.
with 语句可以用于更多的事情。例如:threading.Lock()
lock = threading.Lock()
with lock: # Lock is acquired
do stuff...
# Lock is automatically released.
使用上下文管理器完成的几乎所有事情都可以使用 try: ... finally: ... 完成,但是上下文管理器更易于使用、更舒适、更易读,并且通过实现 __enter__ 和 __exit__ 提供了一个简单的使用界面。
上下文管理器是如何实现的?
或__enter__和__exit__是什么?
通过在普通类中实现__enter__() 和__exit__() 来创建上下文管理器。
__enter__() 告诉上下文管理器启动时要做什么,__exit__() 告诉上下文管理器存在时要做什么(如果发生异常,则将异常提供给 __exit__() 方法)
可以在 contextlib 中找到创建上下文管理器的快捷方式。它将生成器包装为上下文管理器,如下所示:
from contextlib import contextmanager
@contextmanager
def tag(name):
print("<%s>" % name)
yield
print("</%s>" % name)
>>> with tag("h1"):
... print("foo")
...
<h1>
foo
</h1>
示例取自 Python 文档。