【问题标题】: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+ 的答案。

谢谢!

【问题讨论】:

    标签: python inheritance decorator


    【解决方案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")
    

    【讨论】:

      猜你喜欢
      • 2020-01-11
      • 2014-01-14
      • 2012-11-14
      • 2021-01-04
      • 2016-11-26
      • 1970-01-01
      • 2011-11-20
      • 2014-09-06
      • 1970-01-01
      相关资源
      最近更新 更多