apppublic/aidocs/registerfunction.md
2025-10-05 11:23:33 +08:00

6.9 KiB
Raw Blame History

技术文档:函数与协程注册系统

概述

本模块提供了一套基于单例模式的函数注册协程执行管理机制,支持同步函数与异步协程的统一注册、获取与调用。通过 RegisterFunctionRegisterCoroutine 两个核心类,实现了灵活的插件式函数调用架构。

该系统适用于需要动态注册和调用函数/协程的场景(如事件处理器、中间件链、插件系统等),并保证全局唯一实例(单例)。


模块依赖

import asyncio
from inspect import isfunction, iscoroutinefunction
from functools import partial
from appPublic.dictObject import DictObject
from appPublic.worker import awaitify
from appPublic.Singleton import SingletonDecorator
from appPublic.log import info, error

第三方/自定义组件说明:

包/模块 功能
appPublic.dictObject.DictObject 可属性访问的字典对象,用于存储键值对数据
appPublic.worker.awaitify 将同步函数包装为可被 await 调用的形式
appPublic.Singleton.SingletonDecorator 单例装饰器,确保类仅有一个实例
appPublic.log.info, .error 日志输出工具

核心类

1. RegisterFunction —— 函数注册中心(单例)

装饰器:@SingletonDecorator
用途:注册、获取并执行命名的函数或协程。

属性

  • registKW (dict): 存储注册的函数,键为名称,值为函数对象。

方法

__init__(self)

初始化空的函数注册表。

register(name: str, func: callable)

将一个函数或协程注册到指定名称下。

  • 参数
    • name (str): 函数的唯一标识名。
    • func (callable): 要注册的函数或异步协程。
  • 行为
    • func 不是函数或协程,则记录错误日志并返回。
    • 同名函数会被覆盖(最新注册者胜出)。
  • 示例
    rf = RegisterFunction()
    rf.register("hello", lambda: print("Hello"))
    
get(name: str) -> Optional[callable]

根据名称获取已注册的函数。

  • 返回:函数对象,若未找到则返回 None
run(name: str, *args, **kw)

同步执行指定名称的函数。

  • 注意
    • 如果目标是协程函数(async def),会打印提示但不执行,并返回 None
    • 仅适用于普通同步函数。
  • 返回:函数执行结果。
  • 异常处理:若函数未注册,输出错误日志。
async exe(name: str, *args, **kw) -> Any

异步安全执行指定名称的函数或协程。

  • 逻辑
    • 若函数是协程(iscoroutinefunction),直接 await 执行。
    • 若是普通函数,使用 awaitify 包装后执行(使其可在异步上下文中调用)。
  • 返回:函数执行结果(支持 await)。
  • 失败处理:函数不存在时返回 None(静默失败)。

2. RegisterCoroutine —— 协程链注册中心(单例)

装饰器:@SingletonDecorator
用途:按名称注册多个函数/协程,并以逆序方式批量执行(类似中间件栈)。

属性

  • kw (DictObject): 内部存储结构,每个名字对应一个函数列表。

方法

__init__(self)

初始化一个空的 DictObject 来保存函数列表。

register(name: str, func: callable)

向指定名称追加一个函数或协程。

  • 行为
    • 验证输入是否为合法函数。
    • 若该名称尚无注册项,则创建新列表 [func]
    • 否则将 func 追加至列表末尾。
  • 特点:支持同一名称注册多个处理器。
async exe(name: str, *args, **kw)

异步执行该名称下所有注册的函数/协程,顺序为后进先出LIFO

  • 流程
    1. 获取函数列表副本。
    2. 反转列表(实现 LIFO 执行)。
    3. 遍历执行每一个函数:
      • 协程:await f(*args, **kw)
      • 普通函数:直接调用 f(*args, **kw)
  • 返回:始终返回 None
  • 说明:适合用于事件通知、钩子机制等无需聚合返回值的场景。

辅助函数

以下函数提供便捷接口,避免手动实例化单例。

getRegisterFunctionByName(name: str) -> Optional[callable]

获取已注册的函数对象。

  • 参数name 函数名
  • 返回:函数引用或 None

registerFunction(name: str, func: callable)

快捷注册函数。

  • 等价于
    RegisterFunction().register(name, func)
    

async rfexe(rfname: str, *args, **kw) -> Any

异步执行指定名称的注册函数。

  • 等价于
    await RegisterFunction().exe(rfname, *args, **kw)
    

rfrun(rfname: str, *args, **kw) -> Any

同步执行注册函数(仅限同步函数)。

  • 等价于
    RegisterFunction().run(rfname, *args, **kw)
    

使用示例

# 定义测试函数
def x(dic):
    dic['a'] = 'a'
    return dic

async def y(dic):
    dic['b'] = 'b'
    return dic

def z(dic):
    dic['c'] = 1
    return dic

# 主程序
async def main():
    rf = RegisterCoroutine()
    rf.register('test', z)
    rf.register('test', y)
    rf.register('test', x)

    d = {}
    await rf.exe('test', d)  # 按 x → y → z 的反向顺序执行
    print(d)  # 输出: {'a': 'a', 'b': 'b', 'c': 1}

if __name__ == '__main__':
    asyncio.get_event_loop().run_until_complete(main())

⚠️ 注意:由于 exe() 中反转了函数列表,实际执行顺序为最后注册的最先执行。


设计亮点

特性 描述
单例模式 使用 SingletonDecorator 确保全局唯一实例,便于跨模块共享注册表
兼容同步与异步 自动识别协程函数并通过 awaitify 统一异步调用接口
类型安全检查 注册时验证是否为合法函数,防止误注册非可调用对象
灵活调用方式 提供同步 run 与异步 exe 接口,适应不同运行环境
链式协程支持 RegisterCoroutine 支持多函数绑定与逆序执行,适用于中间件/钩子系统

注意事项

  1. 协程不能用 run() 执行run() 方法不会 await 协程,可能导致警告或无效执行。
  2. 函数覆盖问题RegisterFunction.register() 是覆盖式注册,同名函数旧版本将丢失。
  3. 异常捕获建议:当前未封装异常处理,在生产环境中建议在 exe() 外层添加 try-except。
  4. 性能考虑:频繁注册可能导致内存增长,长期运行服务应定期清理无用条目。

总结

本模块构建了一个轻量级、高内聚的函数调度系统,特别适用于:

  • 插件化系统
  • 事件驱动架构
  • 中间件管道设计
  • 异步任务调度

结合 awaitify 与单例模式,实现了简洁而强大的函数注册与异步执行能力,具备良好的扩展性和复用性。