如何为wrapt装饰的BoundFunctionWrapper添加tag属性以标记方法
为wrapt装饰的方法添加tag属性并动态查找
我希望给wrapt装饰的方法对应的BoundFunctionWrapper添加名为tag的属性,这样就能检查实例中带有特定tag值的方法。在多个类上使用该装饰器后,还能查找并执行所有带有指定tag的方法。但当前代码实现无法直接通过实例的方法访问tag属性,请问该方案是否可行?如果可行,我的装饰器实现缺少了什么?有没有更好的动态实现方式?我倾向于动态实现,因为用字典等静态标记方式可能会导致人为错误。
原始代码
import wrapt import inspect def tag_method(tag_message:str): @wrapt.decorator def wrapper(wrapped, instance, args, kwargs): # do some other wrapper stuff besides just tagging return wrapped(*args, **kwargs) setattr(wrapper, 'tag', tag_message) return wrapper # Test Code if __name__ == '__main__': class MyClass: def __init__(self) -> None: pass @tag_method('value_method') def return_value(self, value:int) -> int: return value instance = MyClass() print(instance.return_value(5)) print(inspect.getmembers(instance, predicate=inspect.ismethod)) print(inspect.getmembers(instance, predicate=inspect.ismethod)[1]) print(inspect.getmembers(instance, predicate=inspect.ismethod)[1][1]) # why does this suddenly evaluate to the bound method instead of the BoundFunctionWrapper? print(inspect.getmembers(instance, predicate=inspect.ismethod)[1][1].tag) # want to print the assigned tag 'value_method'
可行性与问题分析
这个方案完全可行。你当前实现的核心问题是:把tag属性添加到了wrapt的Decorator对象上,而非最终生成的FunctionWrapper(或绑定实例后的BoundFunctionWrapper)上。当你访问实例的方法时,得到的是绑定后的BoundFunctionWrapper代理对象,它并不会继承外层Decorator对象的tag属性,因此无法直接通过method.tag获取值。
修正后的装饰器实现
修改装饰器,确保tag属性被添加到最终的包装函数(FunctionWrapper)上,这样绑定实例后的BoundFunctionWrapper会代理该属性:
import wrapt import inspect def tag_method(tag_message: str): @wrapt.decorator def wrapper(wrapped, instance, args, kwargs): # 这里可以添加你的其他包装逻辑 return wrapped(*args, **kwargs) # 自定义装饰器逻辑,给生成的FunctionWrapper添加tag def decorator(wrapped): wrapped_func = wrapper(wrapped) setattr(wrapped_func, 'tag', tag_message) return wrapped_func return decorator # 测试代码 if __name__ == '__main__': class MyClass: def __init__(self) -> None: pass @tag_method('value_method') def return_value(self, value:int) -> int: return value @tag_method('print_method') def print_hello(self): print("Hello World") instance = MyClass() print(instance.return_value(5)) # 获取所有带指定tag的方法 def find_tagged_methods(instance, target_tag): tagged_methods = [] for name, method in inspect.getmembers(instance, predicate=inspect.ismethod): if hasattr(method, 'tag') and method.tag == target_tag: tagged_methods.append((name, method)) return tagged_methods # 查找并执行tag为'value_method'的方法 value_methods = find_tagged_methods(instance, 'value_method') for name, method in value_methods: print(f"执行方法 {name},结果:{method(10)}") # 查找并执行tag为'print_method'的方法 print_methods = find_tagged_methods(instance, 'print_method') for name, method in print_methods: print(f"执行方法 {name}:") method()
关键说明
- 属性传递逻辑:wrapt的
BoundFunctionWrapper是FunctionWrapper的绑定版本,它会代理原FunctionWrapper的属性,因此给FunctionWrapper添加tag后,绑定实例的方法也能直接访问method.tag。 - 动态查找优势:这种方式完全依赖方法对象自身的属性,无需额外维护静态字典,避免了手动维护注册表可能带来的错误,符合你想要的动态实现需求。
- 兼容性:
inspect.ismethod会将BoundFunctionWrapper识别为普通方法,但这不影响属性访问,因为它本质是一个代理对象,会透传对tag属性的访问请求。
扩展优化
如果需要跨多个实例或类批量查找带tag的方法,可以扩展工具函数,支持传入类或实例列表:
def find_tagged_methods_in_objects(objects, target_tag): all_tagged = [] for obj in objects: methods = find_tagged_methods(obj, target_tag) all_tagged.extend([(obj, name, method) for name, method in methods]) return all_tagged
内容的提问来源于stack exchange,提问作者riley-lunar
相关产品推荐
相关产品推荐

