【问题标题】:How to get the name of decorator for function at run time?如何在运行时获取函数的装饰器名称?
【发布时间】:2017-12-07 06:33:54
【问题描述】:

在下面的代码中,Test 类的方法(print_aprint_b)已被两个不同的装饰器装饰。

我如何确定给定的方法(比如说print_a)在运行时被一些特定的装饰器(decorator1)装饰?

简单的解决方案是更改包装函数的名称,即在装饰器方法中将wrapper 更改为wrapper1wrapper2,但问题是我无法控制那部分的代码。

python 有没有类似 Java 的反射 API,这对我有帮助吗?

def my_decorator1(func):
    def wrapper(*args, **kwargs):
        print('I am decorated:1')
        func(*args, **kwargs)
    return wrapper

def my_decorator2(func):
    def wrapper(*args, **kwargs):
        print('I am decorated:2')
        func(*args, **kwargs)
    return wrapper

class Test():

    def __init__(self, a=None, b=None):
        self.a = a
        self.b = b

    @my_decorator1
    def print_a(self):
        print('Value of a is {}'.format(self.a))

    @my_decorator2
    def print_b(self):
        print('Value of b is {}'.format(self.b))


if __name__ == '__main__':

    d = Test.__dict__

    f1 = d.get('print_a')
    f2 = d.get('print_b')

【问题讨论】:

    标签: python decorator python-decorators


    【解决方案1】:

    由于装饰器函数是在装饰时执行的,所以很难得到名字。您可以使用额外的装饰器来解决您的问题。装饰器annotator 写入函数的属性,您可以在装饰函数内部读取此名称:

    def annotator(decorator):
        def wrapper(f):
            g = decorator(f)
            g.decorator = decorator.__name__
            return g
        return wrapper
    
    @annotator(my_decorator1)
    def x():
        print x.decorator
    

    【讨论】:

    • 我无法访问装饰器代码,但我想我需要请求维护者添加它。
    • 如果你修改我的例子,这应该是没有必要的,它适用于你无法请求维护者的装饰者。
    • 明白了,这是新的装饰器,它正在调用实际的装饰器
    【解决方案2】:

    Python 装饰器更多的是用于转换函数,而不是充当简单的元数据标签,就像 Java 注释经常做的那样。所以要做到这一点,我会让装饰器在它包装的函数上设置一个属性(或者可能将它包装在一个特定类型的可调用对象中):

    def my_decorator1(func):
        def wrapper(*args, **kwargs):
            print('I am decorated:1')
            func(*args, **kwargs)
        wrapper.decorator_name = 'my_decorator1'
        return wrapper
    

    然后:

    print(Test.print_a.decorator_name)
    

    或者,在 Python 3.3+ 中,您可以使用 PEP 3155 的 __qualname__ 来识别装饰器。

    【讨论】:

    • OP 说他无权访问装饰器定义。
    猜你喜欢
    • 2020-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-20
    • 1970-01-01
    • 2018-10-25
    • 2016-04-26
    • 2021-12-31
    相关资源
    最近更新 更多