装饰器@wrapper
正在使用wrapt
库来访问包装函数的类,以获取类的名称。在Animal.method()
和foo()
上使用它可以按预期工作。
问题:但是,用Animal.classy
修饰的方法@classmethod
以type
作为其类名,而用Animal.static
修饰的方法{ @staticmethod
无法检索其类。
@wrapper
装饰器函数能否为Animal
和Animal.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
答案 0 :(得分:3)
您遇到的问题是,arg instance
是任何方法的第一个参数的值。因此,对于常规方法,它将是self
的值,对于类方法将是cls
的值。对于静态方法,您没有first / instance参数,因此它的行为就像是一个函数,并且instance
是None
。
因此,让我们遍历您的代码。您调用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()
这可能有助于了解每种情况下需要采取哪些步骤来计算名称。
希望如此。