Skip to main content

Хорошая практика

Выполнение кода при загрузке кога

Большинство людей привыкли выполнять всё в __init__, но это не позволяет выполнять асинхронный код. В этом случае вы можете использовать метод cog_load.

class MyCog(commands.Cog):
def __init__(self, bot: commands.Bot):
self.bot = bot

async def cog_load(self):
self.data = await bot.fetch_database_data()

@commands.slash_command()
async def command(self, interaction: disnake.ApplicationCommandInteraction, user: disnake.User):
await interaction.response.send_message(self.data[user.id])

Перезагрузка вашего бота

Одной из менее известных функций библиотеки disnake являет reload (перезагрузка) - именованный аргумент для вашего бота. Он перезагружает дополнения каждый раз, когда они редактируются, позволяя вам тестировать свой код в реальном времени. Это особенно полезно, если запуск бота занимает много времени, так как будет перезагружаться только одно дополнение.

from disnake.ext import commands

bot = commands.Bot(..., reload=True)
Осторожно

Это следует использовать исключительно для отладки. Пожалуйста, не используйте это в продакшн (production).

Преобразование аргументов в командах

discord.py использовал класс Converter для преобразования аргументов, если они указаны. Однако их было очень сложно использовать с проверкой типов, потому что тип параметка на самом деле никогда не является самим преобразователем.

Disnake стремиться устранить эту проблему, разрешая преобразование только встроенных типов, так как disnake.Member, disnake.Emoji и т.д. Если вы когда-нибудь захотите иметь свой преобразователь, вы должны использовать аргумент converter в Param.

async def convert_data(inter: disnake.ApplicationCommandInteraction, arg: str):
parts = arg.split(",")
return {"a": parts[0], "b": int(parts[1]), "c": parts[2].lower()}


@commands.slash_command()
async def command(
self,
inter: disnake.ApplicationCommandInteraction,
data: Dict[str, Any] = commands.Param(converter=convert_data),
):
...

Если вы хотите иметь возможность использовать классы, вы можете использовать декоратор @classmethod. В качестве альтернативы, установить метод класса в качестве преобразователя, используя converter_method

from dataclasses import dataclass


@dataclass
class Data:
a: str
b: int

@classmethod
async def from_option(cls, inter: disnake.CommandInteraction, arg: str):
a, b = arg.split(",")
return cls(a, int(b))


@commands.slash_command()
async def command(
self,
inter: disnake.CommandInteraction,
data: Data = commands.Param(converter=Data.from_option),
):
...

Цели контекстных команд

Вместо использования inter.target вы можете использовать параметр в вашей команды.

@commands.user_command()
async def command(self, inter: disnake.ApplicationCommandInteraction, user: disnake.User):
await inter.response.send_message(f"Used on {user.mention}")

Описания слэш команды

Вы можете использовать документационные строки для описания команд и аргументов. Всё, что находится перед Parameters, является описанием команды. Всё, что находиться ниже Paramaters, - это описания аргументов.

@commands.slash_command()
async def command(
self,
inter: disnake.ApplicationCommandInteraction,
category: str,
item: str,
details: bool,
):
"""Показать информацию о товаре

Parameters
----------
category: Категория поиска
item: Товар для отображения
details: Подробности, которые нужно узнать
"""

Команды только для серверов

В то время как disnake предоставляет декоратор @commands.guild_only(), он по-прежнему требует вас обрабатывать guild как необязательный в случае, если вы используете линтеры. Для решения этой проблемы вы должны использовтаь GuildCommandInteraction.

# до
@commands.slash_command()
@commands.guild_only()
async def command(inter: disnake.ApplicationCommandInteraction):
assert inter.guild is not None
await inter.send(inter.guild.name)


# после
@commands.slash_command()
async def command(inter: disnake.GuildCommandInteraction):
await inter.send(inter.guild.name)