1

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

  • 假设有十分之一方法的第 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 包
4

1 回答 1

2

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

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

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

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

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

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

于 2021-01-04T11:33:58.410 回答