可以使用class的方法作为contextmanager吗?

Is it okay to use the method of a class as contextmanager?

所以,这是一个简单的代码:

from contextlib import contextmanager

class A:
    
    def __init__(self): 
        self.a = 1
        return

    @contextmanager
    def a2mode(self):
        self.a = 2
        print(self.a)
        yield
        self.a = 1
        print(self.a)
        return
    
ca = A()
with ca.a2mode() as cm:
    print(ca.a+1)

打印:

2
3
1

基本上,我使用 class 的方法来创建一个上下文,其中属性 a 的值为 a=2,而不是其通常的值。基于此执行一些操作,这些操作使用 a 的修改值。在该上下文中操作后,该属性在上下文管理器之前重置为其原始值。

这样做可以吗,还是会导致一些不可预见的问题?它有效,但我不确定这是否是“禁止”代码。

谢谢! 最好的,JZ

那应该没问题,但如果你想确保 a 即使 context-managed 块加注也能重置,你需要使用 try: finally:.

    @contextmanager
    def a2mode(self):
        self.a = 2
        try:
            yield
        finally:
            self.a = 1

此外,如果有更多模式,您需要确保重置为之前的模式...

    @contextmanager
    def a2mode(self):
        old_a = self.a
        self.a = 2
        try:
            yield
        finally:
            self.a = old_a

明确定义 __enter____exit__ 可能更简单,因为 __exit__ 接收在 with 语句中引发的任何异常作为参数。

class A:
    
    def __init__(self): 
        self.a = 1
        return

    def __enter__(self):
        self.a = 2
        print(self.a)

    def __exit__(self, *args):
        self.a = 1
        print(self.a)
        # I don't know the most idiomatic way of checking this...
        if args != (None, None, None):
            exc_type, exc_value, traceback = args
            ...
            # Return a true value to prevent the exception from propagating