@decorator获取@staticmethod和@classmethod

时间:2019-12-18 17:31:39

标签: python python-3.x decorator wrapt

装饰器@wrapper正在使用wrapt库来访问包装函数的类,以获取类的名称。在Animal.method()foo()上使用它可以按预期工作。

问题:但是,用Animal.classy修饰的方法@classmethodtype作为其类名,而用Animal.static修饰的方法{ @staticmethod无法检索其类。

@wrapper装饰器函数能否为AnimalAnimal.classy()获得类名Animal.static()

预期产量

foo
Animal.method
Animal.classy
Animal.static

获得的输出

foo
Animal.method
type.classy
static

要复制的代码

import wrapt
import time

@wrapt.decorator
def wrapper(wrapped, instance, args, kw):
    if instance is not None:
        print(f'\n{instance.__class__.__name__}.{wrapped.__name__}')
    else:
        print('\n' + wrapped.__name__)
    result = wrapped(*args, **kw)
    return result

@wrapper
def foo():
    time.sleep(0.1)

class Animal:
    @wrapper
    def method(self):
        time.sleep(0.1)

    @wrapper
    @classmethod
    def classy(cls):
        time.sleep(0.1)

    @wrapper
    @staticmethod
    def static():
        time.sleep(0.1)

if __name__ == '__main__':
    foo()                   # foo
    Animal().method()       # Animal.method
    Animal.classy()         # type.classy
    Animal.static()         # static

1 个答案:

答案 0 :(得分:3)

您遇到的问题是,arg instance是任何方法的第一个参数的值。因此,对于常规方法,它将是self的值,对于类方法将是cls的值。对于静态方法,您没有first / instance参数,因此它的行为就像是一个函数,并且instanceNone

因此,让我们遍历您的代码。您调用foo,包装器会检查是否设置了instance,这不是因为函数没有获得实例参数,所以它会打印出函数的名称。

接下来,您在method的实例上调用Animal。包装器会检查是否设置了instance,这是因为方法获得了实例参数,因此它会打印出instance的类的名称和方法的名称。

接下来,您在课程classy上致电Animal。包装器将检查是否设置了instance,这是因为类方法获得了实例参数,因此它会打印出instance的类名称和类方法的名称。但是,在这种情况下,instance是定义方法的类,因此当您执行instance.__class__时,它将检索Animal类的元类type。因此,在这种情况下,您真正​​想要的是添加一张支票if isinstance(instance, type),在这种情况下,您想执行print(f"{instance.__name__}.{wrapped.__name__}"),因为在这种情况下,instance是您的类。

最后,您在类static上调用了静态方法Animal。当您声明一个静态方法时,它的行为就像一个普通函数。因此,包装器会检查是否设置了instance并发现没有设置classy,因为函数没有获取实例参数,所以继续进行并仅打印函数的名称。我不知道检测静态方法的标准方法。

因此总而言之,可以回答您的确切问题。是否可以获取static的类名?是。是否可以获取import inspect @wrapt.decorator def universal(wrapped, instance, args, kwargs): if instance is None: if inspect.isclass(wrapped): # Decorator was applied to a class. return wrapped(*args, **kwargs) else: # Decorator was applied to a function or staticmethod. return wrapped(*args, **kwargs) else: if inspect.isclass(instance): # Decorator was applied to a classmethod. return wrapped(*args, **kwargs) else: # Decorator was applied to an instancemethod. return wrapped(*args, **kwargs) 的类名?并不是我所知道的。

有关实现可在不同上下文中应用的装饰器的更多信息,请参见:

特别是提供了示例:

beforeAll()

这可能有助于了解每种情况下需要采取哪些步骤来计算名称。

希望如此。