我有一个类,希望将装饰器应用于该类中的所有函数,而不必向每个函数添加函数装饰器。 我知道有像这里解释的解决方案如何装饰类的所有函数,而无需为每个方法一遍又一遍地键入它?向整个类添加装饰器。但是,我需要访问装饰器中的所有类属性。
因此,像这样使用其他解决方案中的装饰器,我需要能够访问 f 中的所有 cls 属性
def function_decorator(orig_func):
def decorator(*args, **kwargs):
print("Decorating wrapper called for method %s" % orig_func.__name__)
result = orig_func(*args, **kwargs)
return result
return decorator
def class_decorator(decorator):
def decorate(cls):
# this doesn't work
# print(cls.name)
for attr in cls.__dict__:
if callable(getattr(cls, attr)):
setattr(cls, attr, decorator(getattr(cls, attr)))
return cls
return decorate
@class_decorator(function_decorator)
class PersonWithClassDecorator:
def __init__(self, name):
self.name = name
def print_name(self):
print(self.name)
me = PersonWithClassDecorator("Me")
me.print_name()
cls 变量的类型为
有人知道如何实现这一目标吗?我还研究了元类,但遇到了无法访问我的类的属性的相同问题。非常感谢任何帮助:)
__getattribute__
-hook中。每当从类的实例访问任何属性(包括方法)时都会调用此方法。
您可以直接在类中实现
__getattribute__
或创建一个仅包含装饰的 mixin。
from typing import Any
class Decorate:
def __getattribute__(self, item: str) -> Any:
val = super().__getattribute__(item)
if callable(val):
print("Name", self.name) # you can access the instance name here
return function_decorator(val)
return val
然后继承
Decorator
。
class PersonWithClassDecorator(Decorate): ...
这种简单的方法有两个缺点:
function_decorator
被硬编码到 Decorate
类中__init__
、__str__
这样的dunder方法或所有操作符钩子都没有被修饰(在内部它们不是从实例访问,而是从类访问)注意:如果您使用
mypy
(您应该;-)),__getattribute__
钩子将禁用对不存在属性的检测。要解决此问题,请将 __getattribute__
定义包装在 if not typing.TYPE_CHECKING
块中。
function_decorator
实际上可以访问实例属性。您可以相应地更改它并使用您原来的方法。
from collections.abc import Callable
from typing import Any
def function_decorator(orig_function: Callable[..., Any]) -> Callable[..., Any]:
def decorator(self, *args: Any, **kwargs: Any) -> Any:
print(f"Decorating wrapper called for method {orig_func.__name__}: {self.name}")
return orig_function(self, *args, **kwargs)
return decorator
注意:我添加了类型提示,并用
%
-字符串替换了旧的基于 f
的字符串格式。
这有一个小问题:
self.name
仅在__init__
被调用后定义。您可以通过不同的方式处理这个问题:
getattr(self, 'name', None)
- self.name
是 init 之前的 None
__init__
:if orig_func.__name__ == '__init__': return orig_func
__init__
缺点:
@classmethod
和 @staticmethod
function_decorator
现在已与您的班级耦合