Topic 3 of 6

Course materials are currently available in Russian only.

Команды с аргументами

Боту нужны команды: !choose, !roll 2d6, q!help. Разберём, как они устроены внутри.

Префикс и разбор

PREFIX = "q!"


def parse(content):
    if not content.startswith(PREFIX):
        return None                                 # обычное сообщение, не команда
    command, _, rest = content[len(PREFIX):].partition(" ")
    return (command.lower(), rest.strip()) if command else None
  • префикс отрезают по его длине: он бывает из нескольких символов;
  • имя команды приводят к нижнему регистру — пользователи пишут как попало;
  • partition(" ") делит строку по первому пробелу: имя команды и всё остальное.

Удобно хранить команды в словаре «имя → функция» — так новая команда добавляется одной строкой, а неизвестную легко заметить.

Аргументы

Проверяйте аргументы и отвечайте понятной подсказкой. Для сложного формата (2d6) хорошо подходят регулярные выражения:

import re

m = re.fullmatch(r"(\d+)d(\d+)", arg.lower())
if not m:
    await message.channel.send("Формат: !roll 2d6")
    return
count, sides = int(m.group(1)), int(m.group(2))

re.fullmatch требует совпадения всей строки — лишние символы до или после не пройдут.

Случайность

Для игр и бросков удобно завести свой генератор:

import random

rng = random.Random()
rng.choice(["пицца", "суши"])     # случайный элемент
rng.randint(1, 6)                 # от 1 до 6 включительно
rng.seed(42)                      # одинаковая последовательность — для проверок

Готовые команды discord.py

В больших ботах команды не разбирают вручную. В discord.py есть расширение commands:

from discord.ext import commands

bot = commands.Bot(command_prefix="q!", intents=intents)


@bot.command()
async def roll(ctx, dice: str):
    await ctx.send(f"Бросаю {dice}")


bot.run(token)

Оно само разбирает префикс и аргументы, преобразует типы (count: int), строит справку q!help и сообщает об ошибках. А слэш-команды (/roll с подсказками прямо в Discord) делают через bot.tree.command и discord.app_commands. Понимая ручной разбор, разобраться с ними легко.

Итог

  • startswith(PREFIX), отрезать по len(PREFIX), partition(" "), lower();
  • словарь команд, ответ на неизвестную команду;
  • проверка аргументов, re.fullmatch;
  • random.Random(): choice, randint, seed; commands.Bot для больших ботов.