我怎样才能在类中定义装饰器方法?

时间:2012-12-13 02:46:12

标签: python

  

可能重复:
  Can a class method be a decorator?

这是一个例子。

class myclass:
    def __init__(self):
        self.start = False

    def check(self):
        return not self.start

    def doA(self):
        if self.check():
            return
        print('A')

    def doB(self):
        if self.check():
            return
        print('B')

如你所见,我想以装饰器的方式编写检查动作,但经过多次尝试,我发现我只能在课堂外编写方法。请教我如何在课堂上写它,谢谢

编辑:

我可以用这种方式编写代码:

def check(func):
    def checked(self):
        if not self.start:
            return
        func(self)
    return checked

class myclass:
    def __init__(self):
        self.start = False

    @check
    def doA(self):
        print('A')

    @check
    def doB(self):
        print('B')


a = myclass()

a.doA()
a.doB()

a.start = True

a.doA()
a.doB()

但我认为这不是一个好习惯,我想在我的课程中定义检查方法。

3 个答案:

答案 0 :(得分:39)

虽然我并不认为这是完全需要的,但这里是你如何在班上做装饰。由于方法在以后绑定到self的方式,这有点麻烦。通常使用普通功能装饰器,您不必担心这一点。

要求是:

  1. 装饰器需要先在使用它的方法之前定义
  2. 需要使用functools.wrap来正确保存绑定方法
  3. 示例:

    from functools import wraps
    
    class myclass:
        def __init__(self):
            self.start = False
    
        def _with_check(f):
            @wraps(f)
            def wrapped(inst, *args, **kwargs):
                if inst.check():
                    return
                return f(inst, *args, **kwargs)
            return wrapped
    
        def check(self):
            return self.start
    
        @_with_check
        def doA(self):
            print('A')
    
        @_with_check
        def doB(self):
            print('B')
    

    我把它变成了一个受保护的成员,因为它不是别人需要在课堂外使用的东西。它仍然保留了您的公开check()号码,可以自行使用。在调用目标方法之前,装饰器只是先调用它。

答案 1 :(得分:0)

如果您需要修改调用类的多少或所有方法,但您只想将行为更改应用于该类及其子类,只需使用__getattr__()和/或{{ 1}}来改变你的行为。

答案 2 :(得分:0)

认为这就是你所要求的。在def检查之前放置@property装饰器(相同的缩进)使得它可以访问check()的计算值作为属性检查,然后修改你的doA()/ doB()方法以便self.check看起来像属性访问。

class myclass:
    def __init__(self):
        self.start = False

    @property
    def check(self):
        return not self.start

    def doA(self):
        if self.check:
            return
        print('A')

    def doB(self):
        if self.check:
            return
        print('B')