装饰器设计:仅在方法被覆盖时执行
Posted
技术标签:
【中文标题】装饰器设计:仅在方法被覆盖时执行【英文标题】:Decorator design: executing a method only if it has been overridden 【发布时间】:2011-09-07 21:08:37 【问题描述】:我偶然发现了一个棘手的 python 问题。给定(更新):
class A(object):
def run(self):
# This makes possible to determine if 'run' was overridden
if self.run.im_func != A.run.im_func:
print('Running in 0'.format(self.__class__.__name__))
class B(A):
def run(self):
super(B, self).run()
class C(A):
pass
b = B()
c = C()
b.run()
>>> Running in B
c.run()
>>> # nothing :)
你将如何设计@runoverriden 装饰器,它可以在 A.run() 中完成条件语句的工作?
更新: 这段代码的目的是 A.run() 应该记录 run() 调用,只有当它被覆盖时。
谢谢!
【问题讨论】:
我给出了一个我认为是您要求的答案,但是您能否更新问题以解释您为什么想要它?可能有一个更好、更简单的解决方案可以为您提供您想要的,而不是您要求的。 看起来你可以简单地改变你的类层次结构,这样“非覆盖”意味着“超类”意味着“超类方法的主体只是pass
”。当您可以简单地重新排序超类的子类关系时,为什么所有这些都可以工作?
@Duncan,我已经更新了问题的详细信息。如果你还有兴趣,可以看看吗?
虽然您有一个有效的答案,但我认为您应该认真考虑@S.Lott 所说的内容。换句话说,您似乎在倒退。
【参考方案1】:
如果我明白你想要什么:
import functools
def runoverridden(f):
@functools.wraps(f)
def wrapper(self, *args, **kw):
if getattr(self, f.__name__).im_func != wrapper:
return f(self, *args, **kw)
return wrapper
class A(object):
@runoverridden
def run(self):
print('Running in A')
class B(A):
def run(self):
super(B, self).run()
print('Running in B')
class C(A):
pass
b = B()
c = C()
b.run()
c.run()
【讨论】:
哇!非常感谢你,邓肯!像魅力一样工作。【参考方案2】:听起来你想要ABCs。具体来说,abstractmethod 装饰器。
【讨论】:
谢谢,关闭,但不完全是我要找的。 ABCMeta 将在代码“构建”阶段抛出异常。虽然@runoverriden 应该停止基类方法调用,但如果它发现该方法没有在子类中被覆盖。底线 - 一个虚假的方法调用。以上是关于装饰器设计:仅在方法被覆盖时执行的主要内容,如果未能解决你的问题,请参考以下文章