有没有办法编写类装饰器用于回滚目的?

时间:2017-11-22 17:14:17

标签: python contextmanager

我用" revert"写了一堂课。装饰。目的是改变收益率中的类成员,如果发生任何异常,则回复"所有的变化。 :

class A():
    def __init__(self):
        self.kuku = 'old_value'

    @contextmanager
    def revertible_transaction(self):
        old_self = deepcopy(self)
        try:
            yield
        except Exception as e:
            self = old_self
            raise e

    def change_stuff(self):
        with self.revertible_transaction():
            self.kuku = 'new_value'
            raise Exception

我希望self.kuku仍然是' old_value'在我运行change_stuff()之后,但它的新标准是'代替。

任何想法为什么这不起作用以及如何正确地做到这一点?

2 个答案:

答案 0 :(得分:0)

您无法有效地分配给self;您只是在不修改原始对象的情况下更改本地名称引用的对象。如有必要,您需要显式保存要恢复的对象的状态。

@contextmanager
def revertible_transaction(self):
    old_kuku = self.kuku
    try:
        yield
    except Exception:
        self.kuku = old_kuku
        raise

答案 1 :(得分:0)

self中的

revertible_transaction只是一个局部变量。它与self中的change_stuff不同,重新绑定它不会改变任何其他内容。即使您传递了引用(例如,通过yield - 并使用with ... as ...进行分配,您仍然不会替换调用者对change_stuff()方法的任何引用实例

因此,您无法像这样替换self。您需要替换实例属性;你可以通过self.__dict__词典来获取这些词典,通常是:

@contextmanager
def revertible_transaction(self):
    old_state = deepcopy(self.__dict__)
    try:
        yield
    except Exception as e:
        self.__dict__ = old_state
        raise e

这对使用插槽的类不起作用,但代码可以简单地扩展到然后复制MRO中所有__slots__类属性中列出的所有名称。