我使用了下面的Mixin类继承了子类的装饰器。问题是,当一个方法有多个装饰器时,它们就不能被识别(仅仅是最后一个)。例如,如果我有这个类:
class Example(InheritDecoratorsMixin):
@decorator1
@decorator2
def method():
pass然后,任何子类都只继承decorator1,而不继承我想要的decorator2。这里是密辛班:
class InheritDecoratorsMixin:
"""Mixin Class that allows to inherit decorators.
Each subclass of this class will have a '_decorator_registry'
attribute which contains all decorators to be applied.
Each decorator output must contain the attribute 'inherit_decorator'
with itself as the value.
"""
def __init_subclass__(cls, *args, **kwargs):
super().__init_subclass__(*args, **kwargs)
decorator_registry = getattr(cls, '_decorator_registry', {}).copy()
cls._decorator_registry = decorator_registry
# Check for decorated objects in the mixin itself:
for name, obj in __class__.__dict__.items():
if (getattr(obj, 'inherit_decorator', False)
and name not in decorator_registry):
decorator_registry[name] = obj.inherit_decorator
# annotate newly decorated methods in the current subclass:
for name, obj in cls.__dict__.items():
if (getattr(obj, 'inherit_decorator', False)
and name not in decorator_registry):
decorator_registry[name] = obj.inherit_decorator
# finally, decorate all methods annotated in the registry:
for name, decorator in decorator_registry.items():
if (name in cls.__dict__ and getattr(
getattr(cls, name), 'inherit_decorator', None) != decorator):
setattr(cls, name, decorator(cls.__dict__[name]))谢谢你的帮助。
对于任何一个装饰师,我都会这样做:
def decorator(func):
def wrapper(*args, **kwargs):
...
return result
wrapper.inherit_decorator = decorator
return wrapper发布于 2022-07-18 18:19:16
您要做的事情很麻烦,如果您确信这种方法,只需相应地修改您所做的工作:代码中的"decorator_registry“将每个方法名称具体绑定一个修饰器。更改您的代码,以便注册表中的每个条目都是一个列表,而不是单个对象,并维护该列表,而不是在查找新对象时只替换装饰器。此外,您的装饰器,而不是仅仅在"inherit_decorator“方法中用最上面的装饰器本身标记修饰函数,应该在这个属性中维护所有底层装饰器的列表。
我还没有对此进行测试,因为应该有大量的拐角处案例,但总的想法是:
from copy import copy
from functools import wraps
class InheritDecoratorsMixin:
"""Mixin Class that allows to inherit decorators.
Each subclass of this class will have a '_decorator_registry'
attribute which contains all decorators to be applied.
Each decorator output must contain the attribute 'inherit_decorator'
with itself as the value.
"""
def __init_subclass__(cls, *args, **kwargs):
super().__init_subclass__(*args, **kwargs)
decorator_registry = getattr(cls, '_decorator_registry', {}).copy()
cls._decorator_registry = decorator_registry
for class_obj in (__class__, cls):
for name, obj in class_obj.__dict__.items():
if getattr(obj, 'inherit_decorator', False):
new_decorators = [deco for deco in obj.inherit_decorator if deco.__name__ not in decorator_registry.get(name)]
decorator_registry.setdefault(name, []).extend(new_decorators)
# finally, decorate all methods annotated in the registry.
# note that this code might apply some decorators more than once.
for name, decorators in decorator_registry.items():
if name not in cls.__dict__:
continue
method = getattr(cls, name)
new_method = None
for deco in decorators:
if deco in getattr(method, inherit_decorators, []):
continue
new_method = deco(method)
if new_method:
setattr(cls, name, new_method)
def decorator(func):
@wraps(func) # this call preserves name and other properties from the decorated function
def wrapper(*args, **kwargs):
...
return result
decorators = copy(getattr(func, "inherit_decorator", []))
decorators.append(decorator)
wrapper.inherit_decorator = decorators
return wrapperhttps://stackoverflow.com/questions/73012521
复制相似问题