在类中定义装饰器,以 Pythonic 方式影响类变量

问题描述 投票:0回答:1

我正在构建一个 Python 类,我想在其中将一些实例方法标记为“处理程序”,这些方法将在实例被告知运行时应用。下面是一个最小的工作示例。

_handlers = []
def handler_marker(marked_fun):
    _handlers.append(marked_fun)
    return marked_fun


class ManyHandler:

    def __init__(self):
        pass

    def run(self, input):
        for handling_fun in _handlers:
            handling_fun(self, input)

    @handler_marker
    def method_1(self, input):
        print(input)

    @handler_marker
    def method_2(self, input):
        print(input[::-1])

    def method_3(self, input):
        print("I'm not marked.")


if __name__ == "__main__":
    MH = ManyHandler()
    MH.run('Test string')

这行得通,但我不喜欢

_handlers
列表和装饰器在类定义之外。特别是处理程序列表在这里作为类变量感觉更自然。但是,如果我们只是将
_handlers
移到类中并将装饰器更改为

def handler_marker(marked_fun):
    ManyHandler._handlers.append(marked_fun)
    return marked_fun

我们面临两个问题之一:

  1. 如果装饰器是在类之前定义的,我们会得到
    NameError: name 'ManyHandler' is not defined
    ,因为装饰器还不知道 ManyHandler 是什么。
  2. 如果装饰器是在类之后定义的,我们会得到
    NameError: name 'handler_marker' is not defined
    ,因为类在不知道这里的装饰器是什么的情况下无法自行设置。

所以我想把装饰器也放在班级里面。但是要访问类变量

_handlers
,装饰器需要引用
ManyHandler
类。我们不能将类作为参数传递给装饰器,因为在首次应用装饰器时,我们仍在构建类的过程中。

到目前为止,我发现的唯一合理的解决方案是设置一个新类来处理处理程序:

class HandlerHandler:
    _handlers = []

    def __init__(self):
        pass

    @classmethod
    def handler_marker(cls, marked_fun):
        cls._handlers.append(marked_fun)
        return marked_fun


class ManyHandler:
    MetaHandler = HandlerHandler
    _handlers = MetaHandler._handlers
    handler_marker = MetaHandler.handler_marker

    def __init__(self):
        pass

    def run(self, input):
        for handling_fun in type(self)._handlers:
            handling_fun(self, input)

    @handler_marker
    def method_1(self, input):
        print(input)

    @handler_marker
    def method_2(self, input):
        print(input[::-1])

    def method_3(self, input):
        print("I'm not marked.")


if __name__ == "__main__":
    MH = ManyHandler()
    MH.run('Test string')

它有效,但我不相信这是否是 Pythonic(甚至是理智的)。

所以我的问题是:

执行此操作的最 Pythonic 方法是什么?

python python-decorators class-variables
1个回答
2
投票

创建一个单独的类是完全明智的——这就是类的用途,用于封装状态和行为。但是,这是我清理这种方法的方法:

class HandlerRegistry:
    def __init__(self):
        self._handlers = []
    def register(self, fun):
        self._handlers.append(fun)
        return fun
    def __iter__(self):
        yield from self._handlers

class ManyHandler:
    handlers = HandlerRegistry()

    def run(self, input):
        for handling_fun in self.handlers:
            handling_fun(self, input)

    @handlers.register
    def method_1(self, input):
        print(input)

    @handlers.register
    def method_2(self, input):
        print(input[::-1])

    def method_3(self, input):
        print("I'm not marked.")

mh = ManyHandler()
mh.run('Test string')
© www.soinside.com 2019 - 2024. All rights reserved.