获取所有用于函数的装饰器列表

问题描述 投票:0回答:2

我想列出所有用于功能的装饰器,就像这样工作

@a
@b(arg=1)
f():
    pass

get_decorators(f) == ['a', 'b'] 
# or
get_decorators(f) == [a, b] 
python-3.x python-decorators
2个回答
0
投票

带一根胡萝卜,因为我们要在这个问题上掉进兔子洞……

如果装饰器很简单,这可能很简单:

def a(func):
    try:
        func.decorators.append('a')
    except AttributeError:
        func.decorators = ['a']

    # decorator business

    return func

def b(arg):
    def _deco(func)
        try:
            func.decorators.append('b')
        except AttributeError:
            func.decorators = ['b']

        # decorator business

        return func
    return _deco

@a
@b(arg=1)
def my_func():
    pass

print(my_func.decorators)    # Go full python and put attributes on your functions

但是当您将通用功能应用于多个功能时,您可以做什么?你重构当然要使用装饰器!所以,我可以介绍元装饰器。 (我还通过更改

b
返回包装纸来提高赌注)

def deco_tracker(decorator):
    """ Meta-decorator for attaching decorator reference to decorated function
    Applying this decorator to another decorator will result in the final decorated function
    having an attribute called 'decorators' that stores references to it's decorators.
    """
    def deco_wrapper(func):
        returned_func = decorator(func)  # Sometimes a wrapper is returned
        try:
            returned_func.decorators.append(decorator)
        except AttributeError:
            returned_func.decorators = [decorator]
        return returned_func
    return deco_wrapper

@deco_tracker
def a(func):
    # decorator business
    return func

def b(arg):
    @deco_tracker
    def _deco(func)
        def wrapper(*args, **kwargs)
            # decorator business
            return func(*args, **kwargs)
        return wrapper
    return _deco

@a
@b(arg=1)
def my_func():
    pass

print(my_func.decorators)  # [<function b.<locals>._deco 0x19>, <function a at 0x7f>]

存储函数引用比存储名称的字符串表示更容易。它否定了解析包装器的复杂性。

元装饰器可以应用于第三方装饰器,只要它们不返回包装器即可。为此,您需要包装

deco_tracker
以生成
deco_wrapper_tracker
然后将正确的元装饰器变体应用于每个装饰器。对此的增强是检查
isinstance
的第一个传入参数
types.FunctionType
并从那里选择,但这假设采用 args 的装饰器从不采用函数,这是非常安全的选择,但并不理想。如果这得到足够的关注,我将生成示例代码。


0
投票

类似这个问题,虽然历史比较久远,但是提供的方法是可用的:

自省以获取方法上的装饰器名称?

© www.soinside.com 2019 - 2024. All rights reserved.