【问题标题】:Inheritance with decorators用装饰器继承
【发布时间】:2018-04-17 08:37:39
【问题描述】:

这个问题是我在此处发布的上一个问题的扩展: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

Recorder 中的方法 save_to_db 不会在 TestFramework 中执行。我想我在__init_subclass__ 中遗漏了一些东西,我应该遍历每个子类。任何想法?非常感谢!

【问题讨论】:

    标签: python inheritance decorator python-decorators


    【解决方案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))
    

    【讨论】:

      猜你喜欢
      • 2014-03-07
      • 2011-09-18
      • 2011-03-01
      • 2021-07-18
      • 2011-03-23
      • 2014-02-02
      • 2022-01-18
      • 2016-08-01
      • 2011-11-20
      相关资源
      最近更新 更多