跳转至

Depend - 依赖注入🔗

有时, 前面介绍的基础消息链处理器与 Twilight 消息链处理器, 都不能满足我们的需求. 例如, 对某些数据 (好友号, 群号, 权限等) 的主动判断.

此时, Depend 即可助你一臂之力. 我们可利用其构造一个 Decorator.

你可以从 graia.broadcast.builtin.decorators 导入 Depend.

这里所说的 DecoratorGraia Broadcast 的一部分, 而非 Python 的 @decorator 语法糖.

基础: 用于验证的依赖🔗

首先, 我们需要实现一个异步函数. 它可以接收 与事件处理函数相同的参数. 如果我们想对群号进行检查, 可以这样写:

async def check_group(group: Group):
    if group.id != 12345678:
        raise ExecutionStop

这里, 触发的 ExecutionStop 异常, 会结束 Ariadne 对消息的处理, 也就是说, 除了群号为 12345678 以外的群里有消息时, 机器人就不会响应了.

我们用 Depend(check_group) 创建一个 Decorator , 并把它传入 broadcast.receiver 中:

@broadcast.receiver(GroupMessage, decorators=[Depend(check_group)])
async def foo(...): ...
什么是 依赖注入?

依赖注入 这个词听起来挺高大上, 但实际上它的设计思想只有一个: 代码复用.

上面你用 Depend 注入的函数, 基本等价于以下表示:

@broadcast.receiver(GroupMessage)
async def foo(..., group: Group):
    if group.id != 12345678:
        raise ExecutionStop
    ... # 跳过其他代码
@broadcast.receiver(GroupMessage, decorators=[Depend(check_group)])
async def foo(...): ...

运行机器人进行测试, 此时机器人只会响应群号为 12345678 的群里的消息.

提示

你也可以创建一个包装器函数:

def require_group(*group_id: int):
    async def wrapper(group: Group):
        if group.id not in group_id:
            raise ExecutionStop
    return wrapper

@broadcast.receiver(GroupMessage, decorators=[Depend(require_group(12345678, 87654321))])
async def foo(...): ...

Decorator 也可以配合前面提到的基础消息链处理器, 还有 Twilight 一起使用:

@broadcast.receiver(
    GroupMessage,
    dispatchers=[Twilight(Sparkle([UnionMatch("get_data", "data")]))],
    decorators=[Depend(check_group)],
)
async def get_data(...): ...

下一步: 代码复用🔗

Depend 可以返回值, 以便你在函数中直接使用.

比如, 假设你想写一个自动提取消息中图片, 并自动下载其 bytesDepend:

这里我们将使用 Python@decorator 直接包装这个内部函数.

@Depend
async def get_img_bytes(chain: MessageChain) -> List[bytes]:
    result: List[bytes] = []
    for element in chain:
        if isinstance(element, Image):
            result.append(await element.get_bytes())
    return result

# example
@broadcast.receiver(GroupMessage)
async def save_images(..., img_bytes: List[bytes] = get_img_bytes):
    for img_bytes in img_bytes:
        ... # do sth

就是这样! 你可以且应该通过在函数定义的 默认值 位置放置 Decorator 来创建所谓的 “有头装饰器” ,

Depend 包装函数所返回的 所有 值 (包括 None) 都会被传递回去. 同样, 引发的 ExecutionStop 会招致执行的停止.

最后顺口一提, 有头和无头装饰器并不冲突.

社区文档相关章节: 链接