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

如何从经组合装饰器装饰的函数中获取参数?

问题:组合装饰器中获取目标函数的调用参数

现有场景需要通过组合后的remotable装饰器(由remotable_timer和remotable_cache组合而成)修饰test_function,但当前组合写法导致remotable_timer无法获取test_function的实际调用参数(如context、1、2、3),仅能拿到被包装的remotable_cache函数。要求保留组合装饰器的写法,解决参数获取问题。

原代码及输出如下:

import functools

def remotable_timer(fn):
    @functools.wraps(fn)
    def wrapper(*args, **kwargs):
        print('remotable_timer', fn, args, **kwargs)
        result = fn(*args, **kwargs)
        return result
    wrapper.original_fn = fn
    return wrapper

def remotable_cache(fn):
    @functools.wraps(fn)
    def wrapper(*args, **kwargs):
        print('remotable_cache', fn, args)
        result = fn(*args, **kwargs)
        return result

    wrapper.original_fn = fn
    return wrapper

# 原组合写法问题:remotable_timer直接包装remotable_cache函数,而非形成装饰器链
remotable = remotable_timer(remotable_cache)

class TestClass(object):
    @remotable
    def test_function(self, context, *args):
        print('test_function', context, *args)

if __name__ == '__main__':
    test = TestClass()
    test.test_function('context', 1, 2, 3)

原输出:

remotable_timer <function remotable_cache at 0x000002780F7336A8> (<function TestClass.test_function at 0x000002780F733730>,)
remotable_cache <function TestClass.test_function at 0x000002780F733730> (<__main__.TestClass object at 0x000002780F72D898>, 'context', 1, 2, 3)
test_function context 1 2 3

解决方案

修改组合装饰器的实现方式,让remotable成为一个接收目标函数的装饰器,内部先应用remotable_cache再应用remotable_timer,形成完整的装饰器调用链:

import functools

def remotable_timer(fn):
    @functools.wraps(fn)
    def wrapper(*args, **kwargs):
        print('remotable_timer', fn.__name__, args, **kwargs)
        result = fn(*args, **kwargs)
        return result
    wrapper.original_fn = fn
    return wrapper

def remotable_cache(fn):
    @functools.wraps(fn)
    def wrapper(*args, **kwargs):
        print('remotable_cache', fn.__name__, args)
        result = fn(*args, **kwargs)
        return result

    wrapper.original_fn = fn
    return wrapper

# 修改组合逻辑:让remotable作为装饰器,先将目标函数传给remotable_cache,再传给remotable_timer
def remotable(fn):
    return remotable_timer(remotable_cache(fn))

# 或用lambda简化写法:remotable = lambda fn: remotable_timer(remotable_cache(fn))

class TestClass(object):
    @remotable
    def test_function(self, context, *args):
        print('test_function', context, *args)

if __name__ == '__main__':
    test = TestClass()
    test.test_function('context', 1, 2, 3)

修改后的输出:

remotable_timer wrapper (<__main__.TestClass object at 0x0000021A0D6AD898>, 'context', 1, 2, 3) {}
remotable_cache test_function (<__main__.TestClass object at 0x0000021A0D6AD898>, 'context', 1, 2, 3)
test_function context 1 2 3

原理说明

原组合写法remotable = remotable_timer(remotable_cache)是将remotable_cache函数直接作为参数传给remotable_timer,此时remotable_timer的wrapper接收的是目标函数test_function(而非调用参数),导致无法获取实际调用时的参数。

修改后的组合逻辑,让remotable作为一个装饰器函数,先将目标函数test_function传入remotable_cache得到包装后的函数,再将这个包装函数传入remotable_timer,形成remotable_timer→remotable_cache→test_function的调用链。当test_function被调用时,参数会先进入remotable_timer的wrapper,从而实现参数的获取。

内容的提问来源于stack exchange,提问作者Yanchi De Zhang

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 01:50:35