这个需求的背景是这样的,我们在写复杂代码时候,可能会用到 Python 的类继承的方法,即子对象继承父对象的一些属性方法。
在这个过程中,有一些方法的整体逻辑是子对象和父对象都通用的,如果每一个子对象都去重写一次,那么冗余的代码很多、且不优雅。
因此,本文主要解决如果借助装饰器,在父对象定义一个统一的方法,在这个方法中使用子对象的方法!
装饰器,Python 中一种高级特性,它可以让你在不修改原有函数代码的情况下,给函数增加一些新的功能。装饰器本质上是一个接受函数对象作为参数的可调用对象(通常是函数或类),并返回一个新的函数对象。
为了让你更加清楚装饰器的使用,我这里举一个例子:
def my_decorator(func):
def wrapper():
print("Something is happening before the function is called.")
func()
print("Something is happening after the function is called.")
return wrapper
@my_decorator
def say_hello():
print("Hello!")
# 调用函数
say_hello()
输出:
Something is happening before the function is called.
Hello!
Something is happening after the function is called.
my_decorator
是一个装饰器,它接受一个函数 func
作为参数,并返回一个新的函数 wrapper
。在 wrapper
函数中,我们首先打印一条消息,然后调用原始函数 func
,最后再打印一条消息。这样,我们就给原始的 say_hello
函数增加了一些新的功能。
from functools import wraps
from typing import Callable
class Parent:
def do_func(self):
"""
子对象要重写!
:return:
"""
pass
@classmethod
def run(cls, do_func: Callable) -> Callable:
"""
:param do_func: 指的子对象需要重写的方法 do_func
:return:
"""
@wraps(func)
def wrapper(*args, **kwargs):
...
result = do_func(*args, **kwargs)
...
# 返回值根据需要,可以不定义,也可以定义成你需要的返回值
return result
return wrapper
这里有几点说明:
@classmethod
是一个装饰器,用于定义类方法。类方法是绑定到类而不是对象的方法,并且可以通过类或其任何实例进行调用。类方法的第一个参数通常是 cls(虽然名称可以自定义),它代表的是调用该方法的类本身,而不是实例。@wraps
是 Python 中 functools 模块提供的一个装饰器,主要用于保留被装饰函数(或方法)的元信息,如 name、module、doc 等属性。在定义装饰器时使用 @wraps 可以确保装饰后的函数与原始函数具有相同的元数据class Child(Parent):
def do_func(self):
"""
子对象重写父对象的方法
:return:
"""
...
return
@Parent.run
def my_run(self):
return self.do_func()
说明:
do_func
重写了父对象的方法,方便实际的替换调用@Parent.run
装饰器表示被父对象所装饰,实际中实现了父对象调用子对象的方法 do_func
下面给出整体的例子:
from functools import wraps
from typing import Callable
class Parent:
def do_func(self):
"""
子对象要重写!
:return:
"""
pass
@classmethod
def run(cls, do_func: Callable) -> Callable:
"""
:param do_func: 指的子对象需要重写的方法 do_func
:return:
"""
@wraps(func)
def wrapper(*args, **kwargs):
...
result = do_func(*args, **kwargs)
...
# 返回值根据需要,可以不定义,也可以定义成你需要的返回值
return result
return wrapper
class Child(Parent):
def do_func(self):
"""
子对象重写父对象的方法
:return:
"""
...
return
@Parent.run
def my_run(self):
return self.do_func()
if __name__ == '__main__':
child = Child()
child.my_run()
在 child.my_run()
中调用了父对象的方法,子对象的实现非常简洁易懂!