Python装饰器确定方法的执行顺序 [英] Python decorator to determine order of execution of methods

查看:83
本文介绍了Python装饰器确定方法的执行顺序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个基本类 Framework ,其中有3种方法可以由用户设置: initialize handle_event 完成

I have a basic class Framework with 3 methods that can be set by the user: initialize, handle_event and 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 ,这样我就可以编写这样的类:

I would like to create 3 decorators: on_initialize, on_event and on_finalize so that I could write such a class:

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()

这些装饰器确定用户可能添加到类中的可选方法的执行顺序。我认为默认情况下,初始化 handle_event 完成应该采用 precedence = 0 。然后,用户可以使用正确的装饰器添加任何方法,他将知道何时在模拟运行中执行它们。

These decorators determine the order of execution of the optional methods the user may add to the class. I think that by default, initialize, handle_event and finalize should take precedence=0. Then the user could add any method with the right decorator and he will know when they get executed in the simulation run.

老实说,我不知道如何开始这个问题。任何将我推向正确方向的帮助都将受到欢迎!非常感谢。

I have honestly no idea how to get started with this problem. Any help to push me in the right direction will be very welcome! Many thanks.

推荐答案

如果使用的是Python 3.6,这种情况可以利用新的 __ init_subclass__ 方法。创建子类时,子类会在父类上调用它。

If you are using Python 3.6, this is a case that can take advantage of the new __init_subclass__ method. It is called on the superclass by subclasses when they are created.

使用Python3.6,您必须求助于元类。

Withut Python3.6 you have to resort to a metaclass.

装饰器本身可以标记每个方法与所需的数据。

The decorator itself can just mark each method with the needed data.

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 词典中的列表与超类中的列表合并(获取erclass为 cls .__ mro __ [1] ),然后再应用为类属性。

If you will have a complex class hierarchy that should inherit the action methods properly, you wll have to merge the lists in the handlers dictionary with the ones in the superclass (get the superclass as cls.__mro__[1]) before applying then as class attributes.

此外,如果您使用的是任何Python< 3.6,您将需要将 __ init_subclass __ 上的逻辑移至元类。只需将代码原样放在元类的 __ init __ 方法上(并适当调整传入的参数和超级调用),它应该可以正常工作。

Also, if you are using any Python < 3.6, you will need to move the logic on __init_subclass__ to a metaclass. Just put the code as it is on the __init__ method of a metaclass (and adjust the incoming parameters and super call as apropriate), and it should work just the same.

这篇关于Python装饰器确定方法的执行顺序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆