如何在Python类中动态修改装饰器参数值
动态替换装饰器参数的解决方案
问题核心:装饰器是在类定义阶段执行的,此时类的实例还未创建,self.name的值无法传递给装饰器参数。要实现根据实例化时传入的name动态修改装饰器的name参数,需要延迟参数的绑定时机。
方案一:动态装饰器工厂(调用时绑定)
通过自定义装饰器工厂,在方法被调用时从实例中获取动态的name值,再应用traceable装饰器:
import openai from langsmith.run_helpers import traceable from typing import Any def dynamic_traceable(run_type, name_getter=None): def decorator(func): def wrapper(self, *args, **kwargs): # 从实例中获取动态name name = name_getter(self) if name_getter else func.__name__ # 动态应用traceable装饰器并执行方法 traced_func = traceable(run_type=run_type, name=name)(func) return traced_func(self, *args, **kwargs) return wrapper return decorator class LangSmithClass: def __init__(self, name): self.name = name @traceable(run_type="llm", name="openai.ChatCompletion.create") def my_llm(self, *args: Any, **kwargs: Any) -> dict: return openai.ChatCompletion.create(*args, **kwargs) @traceable(run_type="chain") def my_chain(self, prompt: str) -> str: messages = [ {"role": "system", "content": "You are an AI Assistant. "}, {"role": "user", "content": prompt}, ] return self.my_llm(model="gpt-3.5-turbo", messages=messages) @dynamic_traceable(run_type="chain", name_getter=lambda self: self.name) def my_chat_bot(self, text: str) -> str: generated = self.my_chain(text) return generated # 测试 LangSmithClass("ABC").my_chat_bot("how are you") LangSmithClass("XYZ").my_chat_bot("how are you")
优缺点:实现简单,但每次调用方法都会重新执行一次装饰器逻辑,性能略有损耗,适合调用频率不高的场景。
方案二:实例化时重新装饰(更高效)
将原方法的逻辑抽离为私有方法,在类的__init__方法中,根据当前实例的name重新应用traceable装饰器,并替换原方法:
import openai from langsmith.run_helpers import traceable from typing import Any class LangSmithClass: def __init__(self, name): self.name = name # 用实例的name重新装饰私有方法,替换公共方法 self.my_chat_bot = traceable(run_type="chain", name=self.name)(self._my_chat_bot_impl) @traceable(run_type="llm", name="openai.ChatCompletion.create") def my_llm(self, *args: Any, **kwargs: Any) -> dict: return openai.ChatCompletion.create(*args, **kwargs) @traceable(run_type="chain") def my_chain(self, prompt: str) -> str: messages = [ {"role": "system", "content": "You are an AI Assistant. "}, {"role": "user", "content": prompt}, ] return self.my_llm(model="gpt-3.5-turbo", messages=messages) # 原方法逻辑作为私有实现 def _my_chat_bot_impl(self, text: str) -> str: generated = self.my_chain(text) return generated # 测试 LangSmithClass("ABC").my_chat_bot("how are you") LangSmithClass("XYZ").my_chat_bot("how are you")
优缺点:仅在实例化时执行一次装饰逻辑,性能更优,是推荐的解决方案。如果traceable装饰器保留了原函数的__wrapped__属性,也可以直接获取原方法而不用抽离私有方法:
def __init__(self, name): self.name = name # 获取原方法(依赖traceable设置__wrapped__属性) original_func = self.my_chat_bot.__wrapped__ self.my_chat_bot = traceable(run_type="chain", name=self.name)(original_func) # 保留原装饰器写法 @traceable(run_type="chain") def my_chat_bot(self, text: str) -> str: generated = self.my_chain(text) return generated
内容的提问来源于stack exchange,提问作者Talha Anwar
相关产品推荐
相关产品推荐

