khl.py khl.py
主页
文档
示例
  • khl.py (opens new window)
  • khl.py.docs (opens new window)
KOOK (opens new window)
主页
文档
示例
  • khl.py (opens new window)
  • khl.py.docs (opens new window)
KOOK (opens new window)
  • 机器人

    • 初始化
    • 命令
      • 1.基本框架
      • [email protected]相关参数
        • 2.1 命令名字 name
        • 2.2 命令前缀 prefixes
        • 2.3 命令别名 aliases
        • 2.4 正则匹配 regex
        • 2.5 忽略大小写 case_sensitive
        • 2.6 命令规则 rules
        • 2.7 异常处理 exc_handlers
        • 2.8 help和desc
      • 3.命令参数
        • 3.1 单参数示例
        • 3.2 多参数示例
        • 3.3 参数类型
        • 3.4 函数参数缺省值
        • 3.5 不定长参数
      • 4.写在最后
    • 定时任务
    • 在玩状态
  • 消息

    • 消息类型
    • 上传和发送文件或图片
    • 卡片消息
  • 频道

    • 获取频道对象
    • 主动发送消息
  • 用户

    • 获取机器人用户对象
    • 获取用户对象和发送私聊信息
    • 机器人下线
  • 服务器

    • 获取服务器对象
    • 服务器角色操作
    • 设置用户昵称
  • 事件

    • 事件基础处理
  • 其他

    • KOOK客户端获取各类ID
    • 多文件注册机器人命令
    • 配置python的venv虚拟环境
    • 获取图片链接
    • 尝试自己调用api
  • docs
  • 机器人
musnows
2023-05-26
目录
1.基本框架
[email protected]相关参数
2.1 命令名字 name
2.2 命令前缀 prefixes
2.3 命令别名 aliases
2.4 正则匹配 regex
2.5 忽略大小写 case_sensitive
2.6 命令规则 rules
2.7 异常处理 exc_handlers
2.8 help和desc
3.命令参数
3.1 单参数示例
3.2 多参数示例
3.3 参数类型
3.4 函数参数缺省值
3.5 不定长参数
4.写在最后

命令

命令注册,就是告诉机器人应该相应什么命令。

本页面测试代码可见 code/06.cmd.py (opens new window)

# 1.基本框架

注册命令的基本语法如下,包含@bot.command()装饰器,以及一个async def。所修饰的函数的第一个参数始终为Message对象。

from khl import Message

@bot.command() 
async def hello(msg:Message):
    ...

当用户在文字频道中敲出命令名后,机器人会接受用户的命令,并执行hello函数。

# [email protected]相关参数

# 2.1 命令名字 name

在默认情况下,如果没有给装饰器内传入命令名字name,则会采用函数名作为命令名。

比如下方代码,命令名为hello,且采用默认前缀/,用户需要在kook聊天框输入/hello,就能激活这个命令。

@bot.command() 
async def hello(msg:Message):
    ...

如果传入命令名name,则会采用该参数作为命令名字。比如如下代码,命令是/test;

@bot.command(name="test") 
async def hello(msg:Message):
    ...

命令名可以为中文。

# 2.2 命令前缀 prefixes

命令前缀,是用户需要激活某个命令时,应该在命令名之前添加的内容。

khl.py的默认命令前缀是/;

假设命令名字是test,在默认情况下,用户需要在文字频道输入/test,才能激活该命令。

命令前缀可以通过传入一个字符串列表来设置

@bot.command(name="test", prefixes=['/','.']) 
async def hello(msg:Message):
    ...

如上代码中,传入了两个命令前缀。此时在文字频道输入.test和/test都可以激活该命令。

IMG

# 2.3 命令别名 aliases

有的时候,我们希望一个命令能有多个名字,此时就可以使用aliases参数传入一个字符串列表,

@bot.command(name="test",aliases=['tb','ta'])
async def test_cmd(msg: Message):
    ...

此时这个命令就有了三个名字,用户可以通过 /test、/ta、/tb 三种方式呼出该命令。别名中的每个字符串含义和name完全一致,没有优先级之分。

IMG

# 2.4 正则匹配 regex

如果你对已有的前缀+命令名的匹配方式感觉还不够用,还可以传入regex参数来使用正则表达式来匹配用户的输入。

比如如下代码,匹配的就是搜索和点歌这两个关键字

  • ^ 是从头匹配
  • ?: 表示这个括号里的是非捕获组,这个括号里的内容不会被捕获(不会返回在捕获结果里面)
  • | 就相当于or
  • () 就是要捕获的东西
  • .+ 简单来说就是匹配后面的东西,无限次匹配

注意,此处引入了命令参数music_name,后文将解释其作用,你可以先忽略它。

@bot.command(regex=r'^(?:搜索|点歌)(.+)')
async def search_music(msg: Message, music_name: str):  # 以字符串匹配一个命令参数
    print("get search music cmd from", msg.author_id)
    print(f"music name [{music_name}]")
    await msg.reply(f"get search music cmd! [{music_name}]")

这个命令的作用是监听文字频道,只要用户发送 搜索 歌名 或者 点歌 歌名 时,都会调用该命令。

IMG

# 2.5 忽略大小写 case_sensitive

如果你的英文命令需要忽略大小写匹配,则将该参数设置为False(缺省值为True,即进行大小写全匹配)

@bot.command(name="test",case_sensitive=False)
async def test_cmd(msg: Message):
    ...

设置为False后,只要是test这四个字母,无论大小写组合都能呼出该命令。

IMG

# 2.6 命令规则 rules

该参数是一个可执行函数的列表,只有列表中的所有函数返回True的时候,命令才会被响应。

对于规则函数而言,其只有一个Message参数,khl会将消息对象传入这个函数来检查结果。该规则函数可以为async def,也可以为普通def。

def test_rules(msg: Message):
    """这是一个命令规则,只有命令中包含khl才能被执行"""
    if 'khl' in msg.content:
        return True
    return False

@bot.command(name="tf",rules=[test_rules])
async def test_func_cmd(msg: Message,text:str): # 以字符串匹配一个命令参数
    """测试命令"""
    try:
        print(f"get test func cmd from",msg.author_id)
        await msg.reply(f"get test func cmd!")
    except:
        print("test func cmd",traceback.format_exc())

如下图所示,当我们发送/tf 1324时,命令没有被响应。而发送/tf khl时,命令被响应。

IMG

当命令的rules检查没有通过的时候,这次命令的调用会抛出异常,机器人不会给用户任何反馈。

exception raised when handling command: tf
Traceback (most recent call last):
  File "D:\HEXO\khl.py.docs\venv\lib\site-packages\khl\command\command.py", line 143, in handle
    await self._check_rules(msg)
  File "D:\HEXO\khl.py.docs\venv\lib\site-packages\khl\command\command.py", line 173, in _check_rules
    raise Exceptions.Handler.RuleNotPassed(rule)
khl.command.exception.Exceptions.Handler.RuleNotPassed

由于这个异常是在@bot.command中抛出的,而不是我们编写的test_func_cmd函数中抛出的,所以函数体内的try/expect并不能捕获这个异常。而且,该异常中也没有表示是哪一个rules没有检查通过,如果你给定了多个rules,还需要人工debug。

# 2.7 异常处理 exc_handlers

该参数是一个dict,其每个成员是异常类型:对应的处理函数,你可以根据需要传入多个处理函数。

异常处理函数必须是async的,它有三个参数,分别是Command,Exception和Message对象,你可以根据编译器的代码和khl.py的源码看看Command和Message对象的成员,从这些对象中取走你需要的成员变量,来进行错误的处理和用户反馈。

如下示例代码中,我们给exc_handlers传入了一个dict,包含了RuleNotPassed异常和对应的处理函数test_exc_handlers。此时如果命令的规则匹配失败,则会直接调用test_exc_handlers处理函数来处理这个异常,终端中也不会出现异常的traceback打印了。

from khl import Bot, Message, command


def test_rules(msg: Message):
    """这是一个命令规则,只有命令中包含khl才能被执行"""
    if 'khl' in msg.content:
        return True
    return False

async def test_exc_handlers(cmd:command.Command, exception:Exception, msg:Message):
    """异常处理函数"""
    print("get exception from", msg.author_id)
    print("exception type:",type(exception))

@bot.command(name="tf",
             rules=[test_rules],
             exc_handlers={command.exception.Exceptions.Handler.RuleNotPassed: test_exc_handlers})
async def test_func_cmd(msg: Message, text: str):
    """测试命令"""
    try:
        print(f"get test func cmd from", msg.author_id)
        await msg.reply(f"get test func cmd!")
    except:
        print("test func cmd", traceback.format_exc())

出现异常时的效果如下

get exception from 1961572535
exception type: <class 'khl.command.exception.Exceptions.Handler.RuleNotPassed'>

# 2.8 help和desc

这两个参数可以用作代码注释,也可以在出现异常时,从exc_handlers的Command对象中取出用于提示用户。

# 3.命令参数

一个操作可能有多个选项或者输入参数,命令参数就是为此而生的。其本质上是我们@bot.command所修饰的函数的参数。

命令参数在文字频道中以空格作为分割,一个空格就代表是一个参数。

# 3.1 单参数示例

下面给出一个最简单的命令行参数的示例。

该命令有一个命令行参数text,此时用户在文字频道输入/help时并不会被响应,而需要输入/help 一些内容才会被响应。

@bot.command(name="help")
async def help_cmd(msg: Message, text:str):
    """测试命令"""
    print("get help cmd from", msg.author_id, text)
    await msg.reply(f"get help cmd: {text}")

如下图所示,当用户输入命令时缺少参数,或参数多于函数参数,机器人都不会响应

IMG

三次命令输入,只有中间一次命令被正常调用,其余两次会出现参数长度不匹配的异常。

exception raised when handling command: help
Traceback (most recent call last):
  File "D:\HEXO\khl.py.docs\venv\lib\site-packages\khl\command\command.py", line 144, in handle
    self._check_arg_len(to_be_parsed, parsed_args)
  File "D:\HEXO\khl.py.docs\venv\lib\site-packages\khl\command\command.py", line 191, in _check_arg_len
    raise Exceptions.Handler.ArgLenNotMatched(minn, maxx, len(parsed_args))
khl.command.exception.Exceptions.Handler.ArgLenNotMatched
get help cmd from 1961572535 你好
exception raised when handling command: help
Traceback (most recent call last):
  File "D:\HEXO\khl.py.docs\venv\lib\site-packages\khl\command\command.py", line 144, in handle
    self._check_arg_len(to_be_parsed, parsed_args)
  File "D:\HEXO\khl.py.docs\venv\lib\site-packages\khl\command\command.py", line 191, in _check_arg_len
    raise Exceptions.Handler.ArgLenNotMatched(minn, maxx, len(parsed_args))
khl.command.exception.Exceptions.Handler.ArgLenNotMatched

# 3.2 多参数示例

和单参数一样,多参数就是给函数添加上你需要的参数即可,具体参数个数根据你的业务来判断。

@bot.command(name="help")
async def help_cmd(msg: Message, text: str, info: str):
    """测试命令"""
    print("get help cmd from", msg.author_id, text, info)
    await msg.reply(f"get help cmd: {text} | {info}")

效果如下

IMG

控制台输出如下

get help cmd from 1961572535 你好 h

# 3.3 参数类型

python是弱类型语言,但我们可以通过:类型给一个函数的参数指定它的变量类型。这对khl.py的解析也会造成一部分影响。

在下面的示例代码中,我们希望用户传入的参数是一个int类型,即数字。

@bot.command(name="num")
async def num_cmd(msg: Message, index:int):
    """命令参数类型测试"""
    print("get num cmd from", msg.author_id, index)
    await msg.reply(f"get num cmd: {index}")

此时如果用户使用一个非数字的参数,机器人不会响应

IMG

get num cmd from 1961572535 12
get num cmd from 1961572535 -1
exception raised when handling command: num
Traceback (most recent call last):
  File "D:\HEXO\khl.py.docs\venv\lib\site-packages\khl\command\parser.py", line 96, in parse
    arg = await wrap_if_coro(func(msg, client, token))
  File "D:\HEXO\khl.py.docs\venv\lib\site-packages\khl\command\parser.py", line 59, in <lambda>
    int: lambda msg, client, token: int(token),
ValueError: invalid literal for int() with base 10: '你好'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "D:\HEXO\khl.py.docs\venv\lib\site-packages\khl\command\command.py", line 139, in handle
    parsed_args = await self.parser.parse(msg, client, self.lexer.lex(msg), to_be_parsed)
  File "D:\HEXO\khl.py.docs\venv\lib\site-packages\khl\command\parser.py", line 98, in parse
    raise Exceptions.Parser.ParseFailed(param, token, func, e)
khl.command.exception.Exceptions.Parser.ParseFailed
get num cmd from 1961572535 1

而将参数类型声明为str或者不声明参数类型,机器人都能正常响应用户的输入。

IMG

简单而言:当你指明了命令行参数类型,khl.py会将该参数转为对应的类型提供给你。但要注意支持的类型仅限于字符串、整数和小数,其余结构化的参数和对象类型,khl.py就没有办法给你转换了。此时会出现如下异常:

exception raised when handling command: num
Traceback (most recent call last):
  File "D:\HEXO\khl.py.docs\venv\lib\site-packages\khl\command\command.py", line 139, in handle
    parsed_args = await self.parser.parse(msg, client, self.lexer.lex(msg), to_be_parsed)
  File "D:\HEXO\khl.py.docs\venv\lib\site-packages\khl\command\parser.py", line 92, in parse
    raise Exceptions.Parser.NoParseFunc(param, token)
khl.command.exception.Exceptions.Parser.NoParseFunc

你可以给@bot.command传入自定义的Parser来解决这个问题。

# 3.4 函数参数缺省值

除了第一个Message参数外,其余参数都可以给定缺省值。当给定参数缺省值后,用户在使用该命令时就不一定需要传入该参数。

@bot.command(name="help")
async def help_cmd(msg: Message, text: str, info: str=""):
    """测试命令"""
    print("get help cmd from", msg.author_id, text, info)
    await msg.reply(f"get help cmd: {text} | {info}")

如上代码中,info给定了空字符串的缺省值,此时/help 1 2和/help 1都能激活该命令。

注意:Python中函数参数缺省值的规则遵循从右往左提供。

# 3.5 不定长参数

有的时候一个命令需要接受一个包含空格的字符串,比如点歌命令的歌名、搜索命令的搜索内容。我们可以通过可变参数列表来实现这个功能

@bot.command(name="larg")
async def long_arg_cmd(msg: Message,*args):
    """测试命令"""
    print("get long arg cmd from", msg.author_id)
    content = " ".join(args) # 重组为字符串
    await msg.reply(f"get long arg cmd: {content}")

如下图所示,此时任意长度的参数(或者没有参数)都可以激活这个命令。

IMG

# 4.写在最后

慕雪个人建议,一定要在参数不匹配、异常出错的时候让机器人给出错误的反馈,让用户知道自己的命令输入错误了或者处理失败了。否则,机器人不响应命令很容易被误解为“机器人已下线”,从而让用户放弃操作,影响用户体验。

上次更新: 2024/01/24, 10:15:36
初始化
定时任务

← 初始化 定时任务→

Theme by Vdoing | Copyright © 2023-2025 khl.py | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式