Cogs

В определенный момент при разработке бота возникнет ситуация, в которой вы захотите организовать команды, события и какие-то переменные состояния в отдельный класс. Cog’и существуют как раз для этого.

Основы:

  • Каждый cog - класс который является сабклассом cog.Cog.

  • Каждая команда объявляется с декоратором commands.command().

  • Каждый листенер объявляется с декоратором cog.Cog.listener().

  • Cog’и добавляются в бота с помощью метода Bot.add_cog().

  • После чего можно использовать Bot.remove_cog() чтобы удалить их.

Пример

Этот пример создает cog с названием Greetings, который содержит одну команду с названием hello и одно событие.

class Greetings(cog.Cog):
    def __init__(self, bot):
        self.bot = bot
        self._last_user = None

    @cog.Cog.listener()
    async def on_chat_invite_user(self, message):
        user = await self.bot.get_user(message.action.member_id)
        await message.send('Welcome {0.mention}!'.format(user))

    @commands.command()
    async def hello(self, ctx, user_id: int = None):
        """Says hello"""
        user_id = user_id or ctx.author
        user = await self.bot.get_user(user_id)
        if self._last_user is None or self._last_user != user_id:
            await ctx.send('Hello {0.mention}~'.format(user))
        else:
            await ctx.send('Hello {0.mention}... This feels familiar.'.format(user))
        self._last_user = user_id

Пара технических деталей которые стоит взять на заметку:

  • Все листенеры должны быть объявлены с декоратором listener().

  • Название cog’а автоматически берется из названия класса, но может быть переназначено (см. Настройки метаданных).

  • Все команды теперь должны содержать параметр self для возможности использования аттрибутов экземпляра которые используются для сохранения состояния.

Добавление Cog’ов

После объявления cog’ов, их надо добавить в бота с помощью метода add_cog().

bot.add_cog(Greetings(bot))

Этот метод привязывает cog к боту, автоматически добавляя в него все команды и события.

Важно заметить, что cog упоминается с помощью названия, которое можно изменить через Настройки метаданных. Так что если этот ког в определенный момент необходимо удалить, это делается так.

bot.remove_cog('Greetings')

Использование Cog’ов

Так же как и удалить, cog можно получить по его названию. Это позволяет использовать cog для взаимодействия между командами. Например:

class Economy(cog.Cog):
    ...

    async def withdraw_money(self, member, money):
        # implementation here
        ...

    async def deposit_money(self, member, money):
        # implementation here
        ...

class Gambling(cog.Cog):
    def __init__(self, bot):
        self.bot = bot

    def coinflip(self):
        return random.randint(0, 1)

    @commands.command()
    async def gamble(self, ctx, money: int):
        """Gambles some money."""
        economy = self.bot.get_cog('Economy')
        if economy is not None:
            await economy.withdraw_money(ctx.author, money)
            if self.coinflip() == 1:
                await economy.deposit_money(ctx.author, money * 1.5)

Особые методы

Когда cog’и становятся более сложными и количество команд в них растет, наступает момент когда их хочется более сильно персонализировать.

Для этого есть следующие методы:

Для более подробной информации можно посмотреть на эти методы в справочнике.

Настройки метаданных

В основе cog’а лежит метакласс cog.CogMeta, который принимает различные настройки, позволяющие персонализировать некоторые аспекты cog’ов. Для этого необходимо передать аргументы с ключевыми словами в строку объявления класса. Например чтобы поменять имя cog’а, можно передать аргумент name примерно так:

class MyCog(cog.Cog, name='My Cog'):
    pass

Больше опций можно найти в справке к классу cog.CogMeta.

Просмотр свойств

Так как cog’и по сути являются просто классами, некоторые их свойства можно просматривать.

Чтобы получить list команд, можно использовать Cog.get_commands().

>>> cog = bot.get_cog('Greetings')
>>> commands = cog.get_commands()
>>> print([c.name for c in commands])

Чтобы получить события, можно использовать Cog.get_listeners(). Этот метод возвращает список кортежей – первый элемент которого - название события, а второй - сама функция.

>>> for name, func in cog.get_listeners():
...     print(name, '->', func)