You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为单个函数添加多个装饰器并合并配置为最终字典?

解决多个装饰器合并配置字典的问题

核心思路

让所有辅助装饰器(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()

原理说明

  1. 辅助装饰器的作用:layout和documentation不再直接返回字典,而是给被装饰函数添加_instruction_metadata属性,将各自的配置存入这个字典中。返回原函数保证装饰器栈能正常传递函数对象,让后续装饰器继续处理。
  2. 最外层装饰器的汇总:instruction作为最外层装饰器(装饰器应用顺序是从下到上,所以它最后执行),在其wrapper函数中通过getattr获取函数上存储的所有元数据,再与自身的name和callback合并成最终结果字典。
  3. 装饰器顺序:必须将@instruction放在所有辅助装饰器的最上方,这样它才能收集到下层所有装饰器添加的配置。

扩展方案

如果需要支持更多类型的装饰器,只需要按照相同的模式实现:在装饰器中往函数的_instruction_metadata字典中添加对应的键值对即可,无需修改instruction装饰器的逻辑,扩展性强。

内容的提问来源于stack exchange,提问作者Mathias

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 08:00:29