装饰器获取静态方法和类方法的Class.__name__

2024-06-18 11:27:35 发布

您现在位置:Python中文网/ 问答频道 /正文

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

问题:但是,用@classmethod修饰的方法Animal.classytype作为其类名,而用@staticmethod修饰的方法Animal.static无法检索其类。你知道吗

@wrapperdecorator函数是否可以获得Animal.classy()Animal.static()的类名Animal?你知道吗

预期产量

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

Tags: instance函数namefootimedeftypestatic
1条回答
网友
1楼 · 发布于 2024-06-18 11:27:35

问题是arginstance是任何方法的第一个参数的值。所以对于一个常规方法,这将是它的self值,对于一个类方法,这将是cls值。对于静态方法,您没有第一个/实例参数,因此它的行为就像它是一个函数,instanceNone。你知道吗

我们来看看你的代码。调用foo,包装器检查是否设置了instance,因为函数没有获得实例参数,所以它会打印出函数的名称。你知道吗

接下来调用method的实例Animal。包装器检查是否设置了instance,这是因为方法得到一个实例参数,所以它会打印出instance的类名和方法名。你知道吗

接下来调用类Animal上的classy。包装器检查是否设置了instance,这是因为类方法获取实例参数,所以它会打印出instance的类名称和类方法的名称。但是,在本例中,instance是在其上定义方法的类,因此在执行instance.__class__操作时,它将检索Animal类的元类,即type。所以在这种情况下,您实际需要的是添加一个检查if isinstance(instance, type),在这种情况下,您需要执行print(f"{instance.__name__}.{wrapped.__name__}"),因为在这种情况下,instance是您的类。你知道吗

最后,调用类Animal上的静态方法static。当您声明一个静态方法时,它的行为就像一个普通函数。因此,包装器检查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)

这可能有助于理解在每种情况下需要采取哪些步骤来计算名称。你知道吗

希望这有道理。你知道吗

相关问题 更多 >