此问题是我在此处发布的上一个问题的扩展: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
来自save_to_db
的方法Recorder
未在TestFramework
中执行。我想我在__init_subclass__
中缺少一些我应该遍历每个子类的东西。任何的想法?非常感谢!
答案 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))