装饰方法:通过复制

时间:2019-06-13 13:27:05

标签: python exception decorator

我希望在输入异常后,先在副本上进行设置,并且仅在成功用该副本覆盖原始副本的情况下,才能“撤消” try语句中的更改。我似乎有解决方案,但不知道如何将其变成装饰器,因此我的代码保持干燥状态。

说明:

a = 0
try: 
    a = 1
    1/0
except:
    pass

print(a)

输出:1(我希望它是0)

我在这里找到的方法中用于处理异常的装饰器:wrapping class method in try / except using decorator

上面引用的装饰器如下:

def handle_exceptions(f):
    def wrapper(*args, **kw):
        try:
            return f(*args, **kw)
        except Exception as e:
            raise e # or do w/e
    return wrapper

如果我使用这个:

class A:

    def __init__(self):
        self.items = []

    def add_something(item):
        try:
            self.items.append(item)
            1/0
        except Exception as e:
            raise e

然后该项目将被添加到项目列表中(例如,在发生异常之前发生了状态更改)。

我目前拥有的'add_something'方法可以防止这种情况,请尝试首先在副本上进行设置,如果成功,则将覆盖原来的方法:

class A:

    def __init__(self):
        self.items = []

    def add_something(item):
        a_copy = self.items.copy()
        try:
            a_copy.append(item)
            1/0 # fails here, state of self.items remains unchanged
        except Exception as e:
            raise e
        else: # in case no exception is hit, overwrite
            self.items = a_copy

这有效。但是,我需要做多次,因此,我希望使用一个装饰器来处理此问题,以使“ add_something”方法可以保持整洁,理想情况下如下所示(或最接近的方法):

    @exception_handler
    def add_something(item):
        self.items.append(item)
        1/0

我想要一个装饰器@exception_handler,其行为与上面包含try / except / else语句的代码段相同,以保持类方法的整洁。

1 个答案:

答案 0 :(得分:1)

我认为装饰器不是这里的正确解决方案。 1.不同的方法将没有相同的撤消要求,因此装饰器必须将撤消函数作为参数。 2.即使这样做,撤消方法也可能无法访问您在try块中修改的变量。

我认为一种更好的方法是编写一个抽象类(我们将其称为Task),该类具有RunUndo方法,但未实现。然后,您可以编写一个将此类对象作为输入的方法,在try块中执行Run方法,在except块中执行Undo。这样做的好处是该类可以包含共享变量,以便RunUndo都可以访问它。