我有一个基本类Framework
,其中有3种方法可由用户设置:initialize
,handle_event
和finalize
。
这些方法由方法run
执行:
class Framework(object):
def initialize(self):
pass
def handle_event(self, event):
pass
def finalize(self):
pass
def run(self):
self.initialize()
for event in range(10):
self.handle_event(event)
self.finalize()
我想创建3个装饰器:on_initialize
,on_event
和on_finalize
,以便我可以编写这样的类:
class MyFramework(Framework):
# The following methods will be executed once in this order
@on_initialize(precedence=-1)
def say_hi(self):
print('say_hi')
@on_initialize(precedence=0)
def initialize(self):
print('initialize')
@on_initialize(precedence=1)
def start_processing_events(self):
print('start_processing_events')
# The following methods will be executed in each event in this order
@on_event(precedence=-1)
def before_handle_event(self, event):
print('before_handle_event:', event)
@on_event(precedence=0)
def handle_event(self, event):
print('handle_event:', event)
@on_event(precedence=1)
def after_handle_event(self, event):
print('after_handle_event:', event)
# The following methods will be executed once at the end on this order
@on_finalize(precedence=-1)
def before_finalize(self):
print('before_finalize')
@on_finalize(precedence=0)
def finalize(self):
print('finalize')
@on_finalize(precedence=1)
def after_finalize(self):
print('after_finalize')
if __name__ == '__main__':
f = MyFramework()
f.run()
这些装饰器确定用户可以添加到类中的可选方法的执行顺序。我认为默认情况下,initialize
,handle_event
和finalize
应该precedence=0
。然后,用户可以使用正确的装饰器添加任何方法,并且他将知道它们何时在模拟运行中执行。
我真的不知道如何开始解决这个问题。任何帮助推动我朝着正确方向前进的帮助都将非常受欢迎!非常感谢。
答案 0 :(得分:2)
如果您使用的是Python 3.6,则可以利用新的__init_subclass__
方法。它们在创建时由子类在超类上调用。
使用Python3.6,您必须使用元类。
装饰器本身可以用所需数据标记每个方法。
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
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()
如果你有一个应该正确继承动作方法的复杂类层次结构,你必须将handlers
字典中的列表与超类中的列表合并(将超类作为cls.__mro__[1]
在应用之后作为类属性。
此外,如果您使用任何Python< 3.6,您需要将__init_subclass__
上的逻辑移动到元类。只需将代码放在元类的__init__
方法上(并调整传入的参数和超级调用为适当的),它应该工作正常。
答案 1 :(得分:0)
我的想法是使用基于类的装饰器,它很简单,并提供在装饰函数之间共享的中间上下文。所以decorator看起来像这样(我使用的是python3.5):
class OnInitialize:
methods = {}
def __init__(self, precedence):
self.precedence = precedence
def __call__(self, func):
self.methods[self.precedence] = func
def wrapper(*a, **kw):
for precedence in sorted(self.methods.keys()):
self.methods[precedence](*a, **kw)
return wrapper
在装饰时,首先执行 init 并存储优先级值以供进一步使用。其次执行调用,只需将目标函数附加到方法字典中(请注意,调用和方法结构可以自定义,以允许调用具有相同优先级的多个方法)。
另一方面,目标类和方法看起来像这样
class Target:
@OnInitialize(precedence=-1)
def say_hi(self):
print("say_hi")
@OnInitialize(precedence=0)
def initialize(self):
print("initialize")
@OnInitialize(precedence=1)
def start_processing_events(self):
print("start_processing_events")
确保,如果调用以下方法之一,它将使用给定的顺序调用所有修饰的方法。
target = Target()
target.initialize()
希望它有所帮助,如果您对其他内容感兴趣,请在下面给我评论。