【问题标题】:Dynamic decorator for regex matching class methods正则表达式匹配类方法的动态装饰器
【发布时间】:2021-04-07 02:39:14
【问题描述】:

我想在委托类实现等情况下简化方法修饰。

  • 假设第 3 方“服务”类具有十分之一的方法
  • 您想要重写大量的方法来装饰它们
  • 您创建一个委托子类并覆盖选定的方法

这种情况会导致:

class ServiceDelegate(Service):
    @decorator
    def service_method1(self):
        super().service_method1()

    @decorator
    def service_method2(self):
        super().service_method2()

    @decorator
    def service_method3(self):
        super().service_method3()

    ...

这个解决方案似乎效率不高。出于这个原因,可以实现这样的事情:

def methods_decorator(deco, regex: str, base_class=None):
    def f(c: type):
        nonlocal base_class
        # Default base class is the decorated class itself
        if not base_class:
            base_class = c
        avoid_functions: List[str] = ["__init__","__doc__","__module__"]
        # regex functions
        def lmd(i): return i[0] not in avoid_functions and re.fullmatch(regex, i[0])
        funcs = list(filter(lmd, base_class.__dict__.items()))

        for func in funcs:
            print(str(type(func[1])))
            if type(func[1]) == FunctionType:
                setattr(c, func[0], deco(func[1]))
            elif type(func[1]) == StaticMethodType:
                setattr(c, func[0], staticmethod(deco(func[1])))
            elif type(func[1]) == ClassMethodType:
                setattr(c, func[0], classmethod(deco(func[1])))
        return c
    return f


@methods_decorator(deco=decorator1, regex="service_method.*", base_class=Service)
@methods_decorator(deco=decorator2, regex="other_method.*", base_class=Service)
@methods_decorator(deco=decorator3, regex="new.*")
class ServiceDelegate(Service): 
    def new_method(self):
        # Some new func here
    ...

这个想法是“复制”和装饰从基类中选择的正则表达式函数,而不必覆盖它们。此实现适用于我的特定场景。

我对 python 很陌生,所以我不确定这是一个好方法还是一个不好的做法。

  • 是否有任何理由不应用这种解决方案
  • 是否有提供类似功能的现有 python 包

【问题讨论】:

  • 有人问这个吗? :)

标签: python python-3.x overriding python-decorators class-decorator


【解决方案1】:

解决方案是减少打字。但是,它只是将复杂性从添加方法装饰器转移到命名方法和添加魔术类装饰器。

更改方法装饰器的名称和方法名称是一个更好的主意。

class ServiceDelegate(Service):
    @service
    def method1(self):
        super().method1()

    @service
    def method2(self):
        super().method2()

    @service
    def method3(self):
        super().method3()

省略 service_ 前缀并添加 @service 完全不会改变键入字符的数量,并且不再需要魔法类装饰器。

【讨论】:

  • 您好@dong-yuxuan,首先感谢您的回答!是的,当然,方法和装饰器名称只是示例而不是真正的实现。另外考虑到我说的是一个有很多方法的类,而不仅仅是 3 个(在我的具体情况下,有 120 多个方法)。仅计算 get* 方法,我得到了 40 多个。我认为在这种情况下,魔术类装饰器引入的复杂性是合理的。而且这个解决方案可以重复使用,因此收益可能会更大。我只是认为可能存在我不知道的实施风险。
猜你喜欢
  • 2020-08-15
  • 2021-10-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-19
  • 1970-01-01
  • 2011-01-24
相关资源
最近更新 更多