如何在类中声明装饰器,以装饰已经装饰的继承方法?

Posted

技术标签:

【中文标题】如何在类中声明装饰器,以装饰已经装饰的继承方法?【英文标题】:How to declare decorator inside a class, to decorate an already decorated, inherited method? 【发布时间】:2019-10-02 06:23:25 【问题描述】:

我想创建一个装饰器,它是一个类成员,它将装饰一个被装饰的继承方法。

示例代码:

class A(object):
    __metaclass__ = ABCMeta
    def __init__(self):
        pass

    @classmethod
    def the_decorator(cls, decorated):  # <-----this is what i want, with or without self/cls as an argument
        def decorator()
            #do stuff before
            decorated()
            print "decorator was called!"
            #do stuff after
        return decorator

    @abstractmethod
    def inherited():
        raise NotImplemented


class B(A):
    def __init__(self):
        super(B,self).__init__()

    #@A.the_decorator <--- this is what I want, 
    @overrides
    #@A.the_decorator <--- or this
    def inherited():
        print "B.inherited was invoked"

b = B()
b.inherited()

应该输出

B.inherited 被调用

装饰器被调用了!


阅读了this guide on decorators as class members,我仍然无法弄清楚如何使用超类中定义的装饰器来装饰继承的方法。


注意,这里 @overrides 是由 overrides package pip install overrides 定义的


另请注意,我目前使用的是 python 2.7,但我会喜欢 2.7 和 3+ 的答案。

谢谢!

【问题讨论】:

【参考方案1】:

你没那么远!

关键是装饰器将接收一个参数,即装饰函数,因此它只能是一个 statmethod。而且您还忘记了应该使用self 参数声明普通方法。

但是这段代码应该可以工作:

class A(object):
    __metaclass__ = ABCMeta
    def __init__(self):
        pass

    @staticmethod
    def the_decorator(decorated):  # <-----this is what i want, with or without self/cls as an argument
        def decorator(self):
            #do stuff before
            decorated(self)
            print "decorator was called!"
            #do stuff after
        return decorator

    @abstractmethod
    def inherited():
        raise NotImplemented


class B(A):
    def __init__(self):
        super(B,self).__init__()

    @A.the_decorator #<--- this is what I want, 
    @overrides
    #@A.the_decorator <--- or this
    def inherited(self):
        print "B.inherited was invoked"

我可以在 Python 2.7 下测试它,除了 @overrides 装饰器(我在测试中评论过它)

【讨论】:

在问题的第一个链接中,请查看Make it static (don’t) 部分。为什么这里不一样? @Gulzar 这是一个有趣的问题......我在 Python 2.7 和 3.6 中测试了我的代码(使用@staticmethod),它在两者上都运行良好。但请注意,在链接的帖子中,尽管是我个人不喜欢的类方法,但声明装饰器时没有 cls 隐式参数。 @Gulzar Make it static (don't) 段落中描述的问题仅适用于装饰器实现为静态方法使用它来装饰方法的类的情况。您的示例alerady 采用了Declare in another class 段落中概述的解决方案,因此将装饰器方法设为静态非常好。【参考方案2】:

使用 Python 3,您的代码只是缺少一些 self 参数,以便能够使用 b.inherited() 调用函数

class A(object):
    __metaclass__ = ABCMeta
    def __init__(self):
        pass

    @classmethod
    def the_decorator(cls, decorated): 
        def decorator(*args, **kwargs):
            #do stuff before
            decorated(*args, **kwargs)
            print("decorator was called!")
            #do stuff after
        return decorator

    @abstractmethod
    def inherited(self):
        raise NotImplemented


class B(A):
    def __init__(self):
        super(B,self).__init__()

    @A.the_decorator
    @overrides
    def inherited(self):
        print("B.inherited was invoked")

【讨论】:

以上是关于如何在类中声明装饰器,以装饰已经装饰的继承方法?的主要内容,如果未能解决你的问题,请参考以下文章

在类中声明装饰器

如何在类中移动这个方法装饰器模式?

Python 装饰器装饰类中的方法

python_如何在类中定义装饰器

如何在类中使用 Pyomo 装饰器

如何在不显式导入的情况下使新的装饰器在类中可用?