【问题标题】: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 所说的内容。换句话说,您似乎在倒退。

标签: python inheritance decorator


【解决方案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 应该停止基类方法调用,但如果它发现该方法没有在子类中被覆盖。底线 - 一个虚假的方法调用。
猜你喜欢
  • 2020-05-13
  • 2019-10-28
  • 2022-09-29
  • 1970-01-01
  • 1970-01-01
  • 2013-09-22
  • 2021-10-04
  • 2013-12-24
  • 2017-01-31
相关资源
最近更新 更多