2017-11-04 8 views
0

この質問は前に投稿した質問の拡張です。linkデコレータを使用した継承

私はPython 3.6.2を使用しています。私はシステムが継承する汎用クラスFrameworkを持っています。

デコレータon_initialize,on_eventおよびon_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_dbTestFrameworkで実行されていない方法。私は__init_subclass__に何かが足りないと思っています。ここで私は各サブクラスを繰り返していなければなりません。何か案が?どうもありがとう!

答えて

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)) 
+0

@Martijn_Pietersを、ありがとうございました! – agiap

関連する問題