在运行时获取Python装饰器参数

5
有没有一种方法可以在运行时获取装饰器函数的参数?我正在处理的项目非常庞大,重写受影响的代码需要付出巨大的努力。我需要一种动态解决方案来列出分配给一系列函数的所有“类别”。为此,我想避免使用超级hacky的解决方案,比如通过所有模块进行正则表达式匹配。这可以通过检查调用栈中的帧来完成吗?
在我们的环境中,函数是对象方法,并且我们还使用链式装饰器。为了便于理解,我编写了这段代码。
如果不可能,请为该项目的某些部分编写另一个装饰器,尽管这会增加更多的复杂性。但是欢迎任何解决我的问题的建议。
def check(*args):
    # do something project relevant, so just return True
    return True

def decorate(*categories):
    def wrap(f):
        def wrap_check_categories(*args, **kwargs):
            if check(*categories):
                return f(*args, **kwargs)
            else:
                raise Exception
        return wrap_check_categories
    return wrap

def get_categories(f):
    '''Returns decorator parameters'''
    # ... do some magic here
    raise NotImplementedError

@decorate('foo', 'bar')
def fancy_func(*args, **kwargs):
    return args, kwargs

def main():
    ## should output ['foo', 'bar']
    print get_categories(fancy_func)

if __name__ == '__main__':
    main()
1个回答

4

修改修饰器,将类别存储在装饰函数的属性(例如 _args)中:

def check(*args):
    # do something project relevant, so just return True
    return True

def decorate(*categories):
    def wrap(f):
        def wrap_check_categories(*args, **kwargs):
            if check(*categories):
                return f(*args, **kwargs)
            else:
                raise Exception
        wrap_check_categories._args = categories    # <-- store the categories
        return wrap_check_categories
    return wrap

def get_categories(f):
    '''Returns decorator parameters'''
    # ... do some magic here
    return f._args

@decorate('foo', 'bar')
def fancy_func(*args, **kwargs):
    return args, kwargs

def main():
    ## should output ['foo', 'bar']
    print get_categories(fancy_func)

if __name__ == '__main__':
    main()

产出(yields)
('foo', 'bar')

嗨,谢谢你的精彩回答。你能再详细解释一下这是如何工作的吗?我是Python的初学者(尤其是装饰器)。很多关于装饰器的教程都只是简单地定义为def decorator(func):。我对你的代码是如何工作的非常好奇。谢谢! - undefined
啊,好的,这是装饰器工厂。TIL - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接