如何在不修改源码的前提下为已装饰Python函数插入新装饰器?
带参装饰器的提取与堆叠实现方案
核心问题解答
1. 能否直接从func1提取my_dec1到变量?
不能直接提取。带参装饰器@my_dec1(a,b)的执行逻辑是:先调用my_dec1(a,b)返回一个实际的装饰器函数,再用这个函数去装饰func1。被装饰后的func1仅保留了最终的包装函数引用,不会直接存储原my_dec1的入口引用,除非装饰器实现时特意将自身信息绑定到了函数属性中。
2. 能否提取my_dec1的参数以重建装饰器?
可以尝试,但依赖装饰器的实现方式:
- 自定义属性存储参数:如果
my_dec1在实现时,将a、b存入了包装函数的自定义属性(比如func.__dec_args__ = (a, b)),可直接读取该属性获取参数。 - 解析闭包变量:带参装饰器的参数通常会保存在闭包中,可通过
inspect模块解析闭包变量来提取参数。示例代码:
注意:该方法需要匹配import inspect def extract_dec_args(target_func): current = target_func while hasattr(current, '__wrapped__'): closure_info = inspect.getclosurevars(current) # 需根据my_dec1实际的参数名调整判断条件 if 'a' in closure_info.nonlocals and 'b' in closure_info.nonlocals: return closure_info.nonlocals['a'], closure_info.nonlocals['b'] current = current.__wrapped__ return None, None # 执行逻辑 original_func = func1.__wrapped__ dec_a, dec_b = extract_dec_args(func1) if dec_a is not None and dec_b is not None: # 实现目标堆叠:先my_dec2装饰原函数,再用my_dec1(a,b)装饰 final_func = my_dec1(dec_a, dec_b)(my_dec2(original_func))my_dec1闭包中实际的参数变量名,若装饰器基于类实现,闭包结构会不同,需针对性调整。
最终实现逻辑
你已经通过func1.__wrapped__获取了解装饰后的原函数,只要成功提取到a、b,就可以通过my_dec1(a,b)(my_dec2(原函数))的调用顺序,实现与@my_dec1(a,b)、@my_dec2依次装饰原函数完全等价的效果。
内容的提问来源于stack exchange,提问作者Benjamin Chew
相关产品推荐
相关产品推荐

