编写自己的上下文管理器

上下文管理器是实现两个魔术方法 __enter__()__exit__() 的任何对象(尽管它也可以实现其他方法):

class AContextManager():

    def __enter__(self):
        print("Entered")
        # optionally return an object
        return "A-instance"

    def __exit__(self, exc_type, exc_value, traceback):
        print("Exited" + (" (with an exception)" if exc_type else ""))
        # return True if you want to suppress the exception

如果上下文以异常退出,则有关该异常的信息将作为三重 exc_typeexc_valuetraceback 传递(这些变量与 sys.exc_info() 函数返回的变量相同)。如果上下文正常退出,那么这三个论点都将是 None

如果发生异常并传递给 __exit__ 方法,则该方法可以返回 True 以抑制异常,或者在 __exit__ 函数结束时重新引发异常。

with AContextManager() as a:
    print("a is %r" % a)
# Entered
# a is 'A-instance'
# Exited

with AContextManager() as a:
    print("a is %d" % a)
# Entered
# Exited (with an exception)
# Traceback (most recent call last):
#   File "<stdin>", line 2, in <module>
# TypeError: %d format: a number is required, not str

请注意,在第二个示例中,即使在 with 语句的主体中间发生异常,__exit__ 处理程序仍会在异常传播到外部作用域之前执行。

如果你只需要 __exit__ 方法,则可以返回上下文管理器的实例:

class MyContextManager:
    def __enter__(self):
        return self

    def __exit__(self):
        print('something')