如何在不覆盖的情况下为第三方库的类方法追加代码?
不覆盖第三方类方法,追加自定义代码的实现方案
问题场景
需要给第三方库的类方法追加逻辑,同时保留原方法的完整功能,确保后续库更新时原方法的改动能自动生效。例如现有类:
class Test: def Do(self): print('initial')
希望调用test.Do()时,先执行自定义逻辑(比如打印new),再执行原方法的initial,且不能完全覆盖原方法,也无法修改库源码、子类化或使用普通装饰器(因为原类会被外部代码直接引用)。
需求原因
- 完全覆盖原方法会固定代码逻辑,无法同步后续第三方库的更新内容
- 无权修改第三方库的源码
- 原类会被外部代码直接调用,子类化和普通装饰器方案不适用,必须直接修改原类本身
手动复制原函数的实现方式
通过复制原函数的代码对象,再定义新方法替换原方法,确保原方法逻辑被完整保留:
import functools import types class Test: def initial(self, x): print(x) print('initial original') def copy_func(func): # 复制原函数的代码、全局变量等核心属性 new_func = types.FunctionType( func.__code__, func.__globals__, name=func.__name__, argdefs=func.__defaults__, closure=func.__closure__ ) # 保留原函数的元信息(如文档字符串、作者等) new_func = functools.update_wrapper(new_func, func) new_func.__kwdefaults__ = func.__kwdefaults__ return new_func # 复制原方法的副本 original_initial = copy_func(Test.initial) # 定义新方法,在原方法前后追加自定义逻辑 def new_initial(self, x): print('new!') original_initial(self, x) # 替换原类的目标方法 Test.initial = new_initial # 测试效果 test_instance = Test() test_instance.initial('xxx')
更简洁的包装方案
无需手动复制函数,直接保存原方法的引用,通过包装函数实现逻辑追加,这是更高效的实现方式:
class Test: def Do(self): print('initial') # 先保存原方法的引用 original_do = Test.Do # 定义包装函数,追加自定义逻辑 def wrapped_do(self): print('new') # 前置自定义逻辑 original_do(self) # 执行原方法 # print('after new') # 也可添加后置自定义逻辑 # 替换原类的目标方法 Test.Do = wrapped_do # 测试效果 test = Test() test.Do()
如果原方法包含可变参数,可通过*args和**kwargs兼容所有参数情况:
def wrapped_do(self, *args, **kwargs): print('new') original_do(self, *args, **kwargs)
内容的提问来源于stack exchange,提问作者Wealot
相关产品推荐
相关产品推荐

