Python 借助装饰器,实现父对象使用子对象的方法!

2024-01-10 16:21:22


1. 引言

这个需求的背景是这样的,我们在写复杂代码时候,可能会用到 Python 的类继承的方法,即子对象继承父对象的一些属性方法。

在这个过程中,有一些方法的整体逻辑是子对象和父对象都通用的,如果每一个子对象都去重写一次,那么冗余的代码很多、且不优雅。

因此,本文主要解决如果借助装饰器,在父对象定义一个统一的方法,在这个方法中使用子对象的方法!

2. 实践

2.1 装饰器说明

装饰器,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 函数增加了一些新的功能。

2.2 定义一个父类

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

这里有几点说明:

  1. 在Python中,@classmethod 是一个装饰器,用于定义类方法。类方法是绑定到类而不是对象的方法,并且可以通过类或其任何实例进行调用。类方法的第一个参数通常是 cls(虽然名称可以自定义),它代表的是调用该方法的类本身,而不是实例。
  2. 可选,@wraps 是 Python 中 functools 模块提供的一个装饰器,主要用于保留被装饰函数(或方法)的元信息,如 name、module、doc 等属性。在定义装饰器时使用 @wraps 可以确保装饰后的函数与原始函数具有相同的元数据

2.3 定义子类

class Child(Parent):
   def do_func(self):
       """
       子对象重写父对象的方法
       :return:
       """
   		...
   		return
   		
   @Parent.run
   def my_run(self):
       return self.do_func()

说明:

  1. do_func 重写了父对象的方法,方便实际的替换调用
  2. @Parent.run 装饰器表示被父对象所装饰,实际中实现了父对象调用子对象的方法 do_func

3. 整体来看

下面给出整体的例子:

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() 中调用了父对象的方法,子对象的实现非常简洁易懂!

4. 参考

Python基础教程之装饰器详解

文章来源:https://blog.csdn.net/qq_36803941/article/details/135503176
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。