在每个方法运行后更改类中实例变量的最干净方法?

spa*_*omb 0 python metaclass decorator python-3.x

假设我想在运行类中的每个方法后更改一个实例变量。做这个的最好方式是什么?我知道如何使用装饰器(在非常基础的层面上),但不知道如何使用它们修改类中的实例变量。

作为一个例子,我想实现下面显示的内容,但没有从每个方法中显式调用post_method_routine

class MyClass():
    def __init__(self):
        self.state = True

    def post_method_routine(self):
        self.state = False
        print(self.state)

    def method1(self):
        # do stuff
        self.post_method_routine()

    def method2(self):
        # do stuff
        self.post_method_routine()

    def methodN(self):
        # do stuff
        self.post_method_routine()

myinst = MyClass()
myinst.method1() # Output: False
Run Code Online (Sandbox Code Playgroud)

Jor*_*ley 5

装饰器是解决这个问题的干净方法

def post_method(fn):
    def __inner(self,*args,**kwargs):
        result = fn(*args,**kwargs)
        self.post_method_routine()
        return result
    return __inner
Run Code Online (Sandbox Code Playgroud)

现在就用那个......但我不知道你这样做真正完成了什么

class MyClass():
    def __init__(self):
        self.state = True

    def post_method_routine(self):
        self.state = False
        print(self.state)

    @post_method
    def method1(self):
        # do stuff

    @post_method    
    def method2(self):
        # do stuff
Run Code Online (Sandbox Code Playgroud)

如果你想自动将它应用于所有以你可以做的方法开头的方法

class MyClass():
    def __init__(self):
        self.state = True

    def post_method_routine(self):
        self.state = False

    def method1(self):
        # do stuff

    def method2(self):
        # do stuff

for method_name in dir(MyClass):
    if method_name.startswith("method"):
        setattr(MyClass,method_name,post_method(getattr(MyClass,method_name)))
Run Code Online (Sandbox Code Playgroud)

但是我强烈不鼓励这样做,因为它对不经意的观察者来说似乎是“魔法”