跳转至

上下文对象 Context

上下文对象 (Context) 是你大部分情况下接触到的统一用户接口,其提供一致的信息,字段,方法, 提供 Avilla 在任一事件或场景下所获得到的所有信息。

上下文包含的信息🔗

上下文可以用来描述 某人某地某人/物 做了什么,也可以描述一人与另一人间的关系, 在上下文对象中包含了以下字段:

  • Context.client:做了什么事,或是被选中的,行为趋向上 偏主动 的某人。
  • Context.endpoint:被做了什么事,或是相对 client偏被动 的某人。
  • Context.scene:上下文所处的场景。
  • Context.self:在 scene 中,当前账号的 指向
  • Context.mediums:在 clientendpoint 间存在的中间介质,比如 邀请人

这些信息足以以一种完善的方式向开发者提供信息,通过 Python 的各式高级特性, 也能做到像 cx.scene.send_message 这种简洁的表示。

这些字段都是 选择器 (Selector), 简单来说,就是对实际对象的一种直观的指代方式。你需要从前文中包含的链接文档了解更多, 这里给出一个浅显的例子。

Context.client = Selector().land("qq").group("941310484").member("1846913566")
#      实例化对象 ^^^^^^^^^^^

Context.scene = Selector().land("qq").group("941310484")
#                  指代路径 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Context.endpoint = Selector().land("qq").group("941310484")
#                     节点名称 ^^^^   &   ^^^^^

Context.self = Selector().land("qq").group("941310484").member(...)
#                       节点值  ^^^^    &   ^^^^^^^^^^^    &    ^^^

使用🔗

Context 包含以下方法,分别调用 Avilla 的多种抽象功能,你可以在列表项所指向的相应文档中了解详情。

此外,为了方便调用,Context 可以有选择的创建 ContextSelector,这是一个 Selector 的子类, 用于快捷的在 Selector 上调用各种 Context 功能。

# prefer this...
cx.scene.pull(Summary)

# than this...
cx.pull(cx.scene, Summary)

你可以通过这种方式快捷的获取 ContextSelector 实例:

selector = Selector()#.<k>(v) ...
cx[selector]  # -> ContextSelector

Warning

我们不推荐直接通过实例化 Selector 的方式创建 ContextSelector, 这容易带来信息的不完整,如 land 等字段的遗漏。

# 这样……不太好。
cx[Selector().member(...)]
cx[Selector().group(...)]
cx[Selector().file(...)]

更好的办法是使用 Context.into 方法,这会有效的避免这种情况。

# "::" 是对 "land" 的缩写,上下这两种方法等效。
cx.scene.into("::group.member(...)")
cx.scene.into("land.group.member(...)")

# 你也可以使用 "~"
cx.scene.into("~.file(...)")

# 可以使用 kwargs 传参的方式保护表达式不被注入,kwargs 的优先级较字符串内的更高。
cx.scene.into("~.group(111)", group="222")  # => group(222)

除此之外,cx[...] 操作还对 Ryanvk Fn 适用, 如 cx.scene.send_message 其实等同于以下代码:

from avilla.standard.core.message import MessageSend

cx[MessageSend.send](cx.scene, ...)

# 对于 ContextSelector,相当于使用了 functools.partial。
cx.scene[Message.send](...)

对于 avilla.standard.core,内置的方法已经尽可能完全覆盖, 但如果要调用像 Nudge 这样的功能,就需要使用这种方法。

你可以在以下文档处了解相关详情:

Tip

通常的,AvillaEvent 及其派生子类 (eg. MessageReceived) 都可以直接获取 Context...

AvillaLifecycleEvent,即描述了像应用实例可用,应用实例将下线等与 生命周期 相关的事件, 当你接受此类事件时,将没有相应的上下文对象提供。

你通常需要以这样的方法获取事件实例本身,这里以 ApplicationReady 为例:

from avilla.core import ApplicationReady

@broadcast.receiver(ApplicationReady)
async def on_app_ready(event: ApplicationReady):
    # 请勿遗漏 event 的类型注解: ^^^^^^^^^^^^^^^^
    ...