用装饰器继承

时间:2017-11-04 21:08:06

标签: python inheritance decorator python-decorators

此问题是我在此处发布的上一个问题的扩展:link

我使用Python 3.6.2。我有一个我的系统继承的泛型类Framework

我使用装饰器on_initializeon_eventon_finalize来通知必须执行每个方法的Framework。每个装饰器的参数precedence用于确定每个部分的执行顺序(从低到高)。

# 3 decorators 
def on_initialize(precedence=0):
    def marker(func):
        func._initializer = precedence
        return func
    return marker


def on_event(precedence=0):
    def marker(func):
        func._event_handler = precedence
        return func
    return marker


def on_finalize(precedence=0):
    def marker(func):
        func._finalizer = precedence
        return func
    return marker

# Main framework
class Framework:

    def __init_subclass__(cls, *args, **kw):
        super().__init_subclass__(*args, **kw)
        handlers = dict(_initializer=[], _event_handler=[], _finalizer=[])
        for name, method in cls.__dict__.items():
            for handler_type in handlers:
                if hasattr(method, handler_type):
                    handlers[handler_type].append((getattr(method, handler_type), name))

        for handler_type in handlers:
            setattr(cls, handler_type, 
                    [handler[1] for handler in sorted(handlers[handler_type])])

    def _initialize(self):
        for method_name in self._initializer:
            getattr(self, method_name)()

    def _handle_event(self, event):
        for method_name in self._event_handler:
            getattr(self, method_name)(event)

    def _finalize(self):
        for method_name in self._finalizer:
            getattr(self, method_name)()

    def run(self):
        self._initialize()

        for event in range(10):
            self._handle_event(event)

        self._finalize()


class Recorder(Framework):

    @on_finalize(precedence=0)
    def save_to_db(self):
        print('save_to_db')


class TestFramework(Recorder):

    @on_initialize(precedence=0)
    def get_data(self):
        print('get_data')

    @on_initialize(precedence=1)
    def prepare_data(self):
        print('prepare_data')

    @on_event(precedence=0)
    def process_event(self, event):
        print('process_event', event)

    @on_finalize(precedence=1)
    def generate_report(self):
        print('generate_report')

if __name__ == '__main__':
    tf = TestFramework()
    tf.run()

结果:

> get_data 
> prepare_data 
> process_event 0 
> process_event 1 
> process_event 2
> process_event 3 
> process_event 4 
> process_event 5 
> process_event 6
> process_event 7 
> process_event 8 
> process_event 9 
> generate_report

来自save_to_db的方法Recorder未在TestFramework中执行。我想我在__init_subclass__中缺少一些我应该遍历每个子类的东西。任何的想法?非常感谢!

1 个答案:

答案 0 :(得分:1)

您为每个类设置一组新的处理程序,忽略任何基类的处理程序。

不是在handlers词典中使用空列表,而是查找现有列表并从这些列表开始:

def __init_subclass__(cls, *args, **kw):
    super().__init_subclass__(*args, **kw)
    handlers = dict(
        _initializer=getattr(cls, '_initializer', []),
        _event_handler=getattr(cls, '_event_handler', []),
        _finalizer=getattr(cls, '_finalizer', [])))
    # ...

然后你必须删除子类重写的任何方法!

或者,不要只使用当前的类命名空间(通过cls.__dict__),而是使用dir()中可用的组合名称:

def __init_subclass__(cls, *args, **kw):
    super().__init_subclass__(*args, **kw)
    handlers = dict(_initializer=[], _event_handler=[], _finalizer=[])
    for name in dir(cls):
        method = getattr(cls, name)
        for handler_type in handlers:
            if hasattr(method, handler_type):
                handlers[handler_type].append((getattr(method, handler_type), name))