钩子函数详解
什么是钩子函数?
钩子函数是一种特殊的回调函数,它通常被定义在应用程序的某个扩展点,允许框架或库在特定时刻调用用户提供的自定义代码。钩子函数是控制反转(IoC)的典型表现形式——框架决定什么时候调用钩子,而用户实现钩子的具体逻辑。
钩子与普通回调的区别
回调:强调的是“我调用你,你完成后通知我”,通常是异步或事件驱动的。
钩子:强调的是“框架/系统已经定义好了一系列扩展点,用户在这些点上插入自己的逻辑”。钩子通常是同步且有明确的预定义调用时机(例如程序启动、请求处理前/后、关闭时)。
在许多文档和框架中(如 WordPress、Scrapy、Git hooks),钩子函数被命名为before_xxx、after_xxx、on_event等。
Python 中的钩子实现方式
Python 由于动态特性,实现钩子非常简单:基类定义钩子方法(或空方法),子类覆盖;或者直接注册一个函数到内部列表中。
方式一:使用继承(模板方法模式)
class DataProcessor: def process(self, data): data = self.before_process(data) # 核心处理逻辑 data = data.upper() data = self.after_process(data) return data def before_process(self, data): # 默认钩子:什么都不做 return data def after_process(self, data): # 默认钩子 return data class CustomProcessor(DataProcessor): def before_process(self, data): return data.strip() def after_process(self, data): return f"[RESULT] {data}" proc = CustomProcessor() print(proc.process(" hello world ")) # 输出: [RESULT] HELLO WORLD方式二:使用函数注册表(更灵活的钩子系统)
class HookManager: def __init__(self): self._hooks = {} def register(self, hook_name: str, hook_func): self._hooks.setdefault(hook_name, []).append(hook_func) def run_hooks(self, hook_name: str, context): for hook in self._hooks.get(hook_name, []): context = hook(context) return context # 创建钩子管理器实例 hooks = HookManager() # 用户注册钩子 def trim_hook(text): return text.strip() def capitalize_hook(text): return text.capitalize() hooks.register("preprocess", trim_hook) hooks.register("preprocess", capitalize_hook) # 在框架内部调用钩子 def process_user_input(user_input: str): # 调用所有注册到 "preprocess" 的钩子 user_input = hooks.run_hooks("preprocess", user_input) return f"最终输出: {user_input}" print(process_user_input(" hello world ")) # 输出: 最终输出: Hello world方式三:利用装饰器(现代 Python 风格)
import functools class HookClient: hooks = {} @classmethod def hook(cls, name): def decorator(func): cls.hooks.setdefault(name, []).append(func) return func return decorator @classmethod def run_hook(cls, name, *args, **kwargs): results = [] for func in cls.hooks.get(name, []): results.append(func(*args, **kwargs)) return results # 用户定义钩子 @HookClient.hook("before_save") def log_before_save(data): print(f"准备保存: {data}") return data @HookClient.hook("after_save") def log_after_save(data): print(f"已保存: {data}") # 框架代码 def save_data(data): HookClient.run_hook("before_save", data) # ... 实际保存逻辑 ... HookClient.run_hook("after_save", data) save_data({"id": 1, "name": "test"})输出:
准备保存: {'id': 1, 'name': 'test'}
已保存: {'id': 1, 'name': 'test'}
钩子函数是框架扩展的基石,让用户代码能够安全地植入到框架的特定流程中。
