如何在类中声明装饰器,以装饰已经装饰的继承方法?
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")
【讨论】:
以上是关于如何在类中声明装饰器,以装饰已经装饰的继承方法?的主要内容,如果未能解决你的问题,请参考以下文章