編寫自己的上下文管理器

上下文管理器是實現兩個魔術方法 __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')