首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用多个装饰器继承装饰器

用多个装饰器继承装饰器
EN

Stack Overflow用户
提问于 2022-07-17 14:13:01
回答 1查看 68关注 0票数 0

我使用了下面的Mixin类继承了子类的装饰器。问题是,当一个方法有多个装饰器时,它们就不能被识别(仅仅是最后一个)。例如,如果我有这个类:

代码语言:javascript
复制
class Example(InheritDecoratorsMixin): 
  
  @decorator1
  @decorator2
  def method(): 
    pass

然后,任何子类都只继承decorator1,而不继承我想要的decorator2。这里是密辛班:

代码语言:javascript
复制
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]))

谢谢你的帮助。

对于任何一个装饰师,我都会这样做:

代码语言:javascript
复制
def decorator(func): 
  def wrapper(*args, **kwargs):

    ...
    
    return result

  wrapper.inherit_decorator = decorator
  return wrapper
EN

回答 1

Stack Overflow用户

发布于 2022-07-18 18:19:16

您要做的事情很麻烦,如果您确信这种方法,只需相应地修改您所做的工作:代码中的"decorator_registry“将每个方法名称具体绑定一个修饰器。更改您的代码,以便注册表中的每个条目都是一个列表,而不是单个对象,并维护该列表,而不是在查找新对象时只替换装饰器。此外,您的装饰器,而不是仅仅在"inherit_decorator“方法中用最上面的装饰器本身标记修饰函数,应该在这个属性中维护所有底层装饰器的列表。

我还没有对此进行测试,因为应该有大量的拐角处案例,但总的想法是:

代码语言:javascript
复制
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 wrapper
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73012521

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档