Python装饰器实现Hook类

背景

最近有个新的需求是使用Redmine进行一些提交前后的处理,备忘下一些思路

实现思路

为了统一代码的路径以及调用方式,封装了一个Hook类,按理来说是可以对所有类似的代码使用的,这里使用了Python装饰器,统一对同一个命名类的进行处理,相当于定义了函数的路由
核心代码见下:
Hook.py

from functools import wraps

class Hook():
    hook_registry = {}
    STOP_EXECUTION = "STOP"  # 将停止标识封装为类属性

    @classmethod
    def registry_hook(cls, hook_name, priority=0):
        def hook_decorator(func):
            @wraps(func)
            def wrapped_function(*args, **kwargs):
                print(f"Hook '{hook_name}' is triggered for {func.__name__}")
                return func(*args, **kwargs)

            cls.hook_registry.setdefault(hook_name, []).append((priority, wrapped_function))
            cls.hook_registry[hook_name].sort(key=lambda x: x[0], reverse=True)  # 按优先级降序排序
            return wrapped_function

        return hook_decorator

    @classmethod
    def trigger_hooks(cls, hook_name, *args, **kwargs):
        if hook_name in cls.hook_registry:
            for priority, func in cls.hook_registry[hook_name]:
                result = func(*args, **kwargs)
                if result == cls.STOP_EXECUTION:  # 使用类属性停止执行链
                    print(f"Execution chain stopped at hook '{hook_name}' by {func.__name__}")
                    break

用法示例:

import Hook

hook = Hook()

@hook.registry_hook("after_commit", priority=2)
def test(params):
    print(f"test function called with params: {params}")
    return svn_hook.STOP_EXECUTION

@hook.registry_hook("after_commit", priority=1)
def test2(params):
    print(f"test2 function called with params: {params}")

@hook.registry_hook("after_commit", priority=3)
def test3(params):
    print(f"test3 function called with params: {params}")

# 模拟触发钩子
svn_hook.trigger_hooks("after_commit", "stop")

输出

Hook 'after_commit' is triggered for test3
test3 function called with params: stop
Hook 'after_commit' is triggered for test
test function called with params: stop
Execution chain stopped at hook 'after_commit' by test
posted @ 2024-07-29 17:32  CanghaoLi  阅读(70)  评论(0)    收藏  举报