如何从修饰的子类方法中调用重写的超类方法

How to call an overriden superclass method from within a decorated subclass method

我正在尝试创建一个装饰器,当 class 方法被子 class 覆盖时,它会扩展该方法的功能。这是一个最小的例子:

class Parent(object):
    def __init__(self):
        return

    def say_hello(self):
        print('Parent says hello')

class Child1(Parent):
    def __init__(self):
        super().__init__()

    def say_hello(self):
        print('Child says hello')

child = Child1()
child.say_hello() # this will print 'Child says hello'

我想创建一个装饰器,除了子方法外,它还会执行父方法。

def extendedmethod(method):
    def wrapper(obj):
        # call the method as defined by the superclass
        method(obj) # call the method defined by the subclass
    return wrapper

class Child2(Parent):
    def __init__(self):
        super().__init__()

    @extendedmethod
    def say_hello(self):
        print('Child says hello')

child = Child2()
child.say_hello() # I want this to print 'Parent says hello' then 'Child says hello'

我想我真正想问的是如何访问从装饰器内部派生的 superclass,subclass?

在显式代码中,我们将编写以下内容:

class Child2(Parent):
    def say_hello(self):
        super().say_hello()  # call baseclass method
        print('Child says hello')

此处super()的argument-less形式编译为super(__class__, self),其中__class__ = Child2。重要的部分是 super 需要实例 selfowning class.


获取实例很简单——它在调用时传递给装饰方法。挑战在于提取修饰方法所在的 class。

一种方法是将装饰器设计为描述符(类似于property)——描述符可以定义一个method __set_name__ to receive their name and owning class. In addition, we must define __get__ to satisfy the descriptor protocol and receive self, as well as __call__来实际调用方法:

class extendedmethod:
    """Decorator to call the superclass method before a method"""
    def __init__(self, method, owner=None):
        self.method = method
        self.owner = owner

    def __set_name__(self, owner, name):
        self.owner = owner

    def __get__(self, instance, owner=None):
        # self.__call__ with `__m_self__` and `__m_cls__` filled in
        return partial(self, instance, owner)

    def __call__(self, __m_self__, __m_cls__, *args, **kwargs):
        # self: the decorator instance
        # __m_self__: the `self` seen by a method
        # __m_cls__: the `cls` seen by a classmethod
        # super(__class__, self).say_hello ------------------------v 
        #      v super(__class__, self) ----v
        getattr(super(self.owner, __m_self__), self.method.__name__)(*args, **kwargs)
        return self.method.__get__(__m_self__, __m_cls__)(*args, **kwargs)

这个装饰器可以直接应用到一个方法上去调用它的superclass方法:

class Child2(Parent):
    @extendedmethod
    def say_hello(self):
        print('Child says hello')

Child2().say_hello()
# Parent says hello
# Child says hello