@decorator 获得@staticmethod 和@classmethod 的Class.__name__
@decorator get Class.__name__ of @staticmethod and @classmethod
装饰器 @wrapper
正在使用 wrapt
库访问包装函数的 class 以获取 class 的名称。在 Animal.method()
和 foo()
上使用它按预期工作。
问题: 但是,用 @classmethod
修饰的方法 Animal.classy
给出 type
作为其 class 名称,并且用 @staticmethod
修饰的方法 Animal.static
无法检索其 class.
@wrapper
装饰器函数是否可以为 Animal.classy()
和 Animal.static()
获取 class 名称 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
您遇到的问题是 arg instance
是任何方法的第一个参数的值。因此,对于常规方法,这将是 self
值,而对于 class 方法,它将是 cls
值。对于静态方法,您没有 first/instance 参数,因此它的行为就好像它是一个函数并且 instance
是 None
.
那么让我们来看看你的代码。你调用 foo
,你的包装器检查是否设置了 instance
,它不是因为函数没有获得实例参数,所以它打印出函数的名称。
接下来在 Animal
的实例上调用 method
。您的包装器检查是否设置了 instance
,这是因为方法获得了一个实例参数,所以它打印出 instance
的 class 的名称和方法的名称。
接下来您在 class Animal
上调用 classy
。您的包装器检查是否设置了 instance
,这是因为 class 方法获得了一个实例参数,所以它打印出 instance
的 class 的名称和 instance
的名称class 方法。但是,在这种情况下,instance
是定义该方法的 class,因此当您执行 instance.__class__
时,它会为您的 Animal
[=63] 检索元 class =] 即 type
。所以在这种情况下你真正想要的是添加一个检查 if isinstance(instance, type)
并且在这种情况下你想要做 print(f"{instance.__name__}.{wrapped.__name__}")
因为实例是你的 class 在这种情况下。
最后,您在 class Animal
上调用了静态方法 static
。当您声明一个静态方法时,它的行为就像一个普通函数。所以你的包装器检查 instance
是否被设置并发现它没有,因为函数没有获得实例参数,所以继续并打印函数的名称。我不知道检测静态方法的标准方法。
所以总结一下回答你的确切问题。是否可以为 classy
获取 class 名称?是的。是否可以为 static
获取 class 名称?不是我知道的。
有关实现可应用于不同上下文的装饰器的更多信息,请参阅:
它特别提供了示例:
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)
这可能有助于理解在每种情况下需要采取哪些步骤来计算名称。
希望这是有道理的。
装饰器 @wrapper
正在使用 wrapt
库访问包装函数的 class 以获取 class 的名称。在 Animal.method()
和 foo()
上使用它按预期工作。
问题: 但是,用 @classmethod
修饰的方法 Animal.classy
给出 type
作为其 class 名称,并且用 @staticmethod
修饰的方法 Animal.static
无法检索其 class.
@wrapper
装饰器函数是否可以为 Animal.classy()
和 Animal.static()
获取 class 名称 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
您遇到的问题是 arg instance
是任何方法的第一个参数的值。因此,对于常规方法,这将是 self
值,而对于 class 方法,它将是 cls
值。对于静态方法,您没有 first/instance 参数,因此它的行为就好像它是一个函数并且 instance
是 None
.
那么让我们来看看你的代码。你调用 foo
,你的包装器检查是否设置了 instance
,它不是因为函数没有获得实例参数,所以它打印出函数的名称。
接下来在 Animal
的实例上调用 method
。您的包装器检查是否设置了 instance
,这是因为方法获得了一个实例参数,所以它打印出 instance
的 class 的名称和方法的名称。
接下来您在 class Animal
上调用 classy
。您的包装器检查是否设置了 instance
,这是因为 class 方法获得了一个实例参数,所以它打印出 instance
的 class 的名称和 instance
的名称class 方法。但是,在这种情况下,instance
是定义该方法的 class,因此当您执行 instance.__class__
时,它会为您的 Animal
[=63] 检索元 class =] 即 type
。所以在这种情况下你真正想要的是添加一个检查 if isinstance(instance, type)
并且在这种情况下你想要做 print(f"{instance.__name__}.{wrapped.__name__}")
因为实例是你的 class 在这种情况下。
最后,您在 class Animal
上调用了静态方法 static
。当您声明一个静态方法时,它的行为就像一个普通函数。所以你的包装器检查 instance
是否被设置并发现它没有,因为函数没有获得实例参数,所以继续并打印函数的名称。我不知道检测静态方法的标准方法。
所以总结一下回答你的确切问题。是否可以为 classy
获取 class 名称?是的。是否可以为 static
获取 class 名称?不是我知道的。
有关实现可应用于不同上下文的装饰器的更多信息,请参阅:
它特别提供了示例:
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)
这可能有助于理解在每种情况下需要采取哪些步骤来计算名称。
希望这是有道理的。