如何从修饰的子类方法中调用重写的超类方法
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
需要实例 self
和 owning 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
我正在尝试创建一个装饰器,当 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
需要实例 self
和 owning 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