如何为单个函数添加多个装饰器并合并配置为最终字典?
解决多个装饰器合并配置字典的问题
核心思路
让所有辅助装饰器(layout、documentation)将配置存储在被装饰函数的自定义属性中,最后由最外层的instruction装饰器收集所有配置并合并为最终字典。
修改后的代码实现
def instruction(name): def decorator(callback): def wrapper(self, *args, **kwargs): # 收集所有装饰器添加的元数据,默认空字典 metadata = getattr(callback, '_instruction_metadata', {}) # 合并所有配置项 return { "name": name, "callback": lambda: callback(self, *args, **kwargs), **metadata } return wrapper return decorator def layout(config): def decorator(func): # 初始化或更新函数的元数据字典 if not hasattr(func, '_instruction_metadata'): func._instruction_metadata = {} func._instruction_metadata['layout'] = config return func # 返回原函数,保证后续装饰器能继续处理 return decorator def documentation(text): def decorator(func): if not hasattr(func, '_instruction_metadata'): func._instruction_metadata = {} func._instruction_metadata['documentation'] = text return func return decorator # 装饰器顺序注意:instruction放在最外层,确保能收集所有下层装饰器的配置 @instruction("poke") @layout({"address": 2, "data": 1}) @documentation("handle poke instruction") def instruction_poke(self): address = self.serial_read_bytes(2) data = self.serial_read_bytes(1) print(f"poke {address=} {data=}") # ... def main(): # 模拟带有serial_read_bytes方法的对象 class MockSerial: def serial_read_bytes(self, n): return bytes([0]*n) self = MockSerial() instruction = instruction_poke(self) print(instruction) # 输出结果: # { # 'name': 'poke', # 'callback': <function instruction.<locals>.decorator.<locals>.wrapper.<locals>.<lambda> at 0x...>, # 'layout': {'address': 2, 'data': 1}, # 'documentation': 'handle poke instruction' # } if __name__ == "__main__": main()
原理说明
- 辅助装饰器的作用:
layout和documentation不再直接返回字典,而是给被装饰函数添加_instruction_metadata属性,将各自的配置存入这个字典中。返回原函数保证装饰器栈能正常传递函数对象,让后续装饰器继续处理。 - 最外层装饰器的汇总:
instruction作为最外层装饰器(装饰器应用顺序是从下到上,所以它最后执行),在其wrapper函数中通过getattr获取函数上存储的所有元数据,再与自身的name和callback合并成最终结果字典。 - 装饰器顺序:必须将
@instruction放在所有辅助装饰器的最上方,这样它才能收集到下层所有装饰器添加的配置。
扩展方案
如果需要支持更多类型的装饰器,只需要按照相同的模式实现:在装饰器中往函数的_instruction_metadata字典中添加对应的键值对即可,无需修改instruction装饰器的逻辑,扩展性强。
内容的提问来源于stack exchange,提问作者Mathias
相关产品推荐
相关产品推荐

