pythondiscord.py

Access class properties or methods from within a commands.Command


I'm building a Discord bot. The bot should store some information into some internal variables to be accessed at a later time. To do so I'm structuring it as a class (as opposed to many examples where the commands are outside a class definition). However, I discovered that when you use the @commands.command(name='test') decorator, the method becomes a kind of "static" method and no longer receives the object as first input.

Given this, is there any way I can access class properties (such as an_instance_property in the example below) and/or class methods (such as a_class_method in the example below)?

If this is the wrong approach, what could be a better approach for a bot with an internal state?

import discord
from discord.ext import commands

with open('TOKEN', 'r') as f:
    TOKEN = f.read()

class mybot(commands.Bot):
    def __init__(self):
        intents = discord.Intents.default()
        super().__init__(command_prefix="!", intents=intents)
        self.add_command(self.test)

        self.an_instance_property = [] # <----

    def a_class_method(x): # <----
        return x

    @commands.command(name='test')
    async def test(ctx, *args):
        # How can I access self.an_instance_property from here?
        # How can I call self.a_class_method from here?
        return

bot = mybot()
bot.run(TOKEN)

Solution

  • My recommendation is that you avoid defining commands inside your bot class. There is a more appropriate way to do this, which is using cogs/extensions. See this topic where commands are created in a separate file (extension) and only loaded into the bot class: https://stackoverflow.com/a/78166456/14307703

    Also know that the Context object always carries the instance of your bot. So you can access all the properties of the class like this:

    class MyBot(commands.Bot):
        def __init__(self):
            intents = discord.Intents.default()
            super().__init__(command_prefix="!", intents=intents)
            self.add_command(self.test)
    
            self.an_instance_property = [] # <----
    
        def a_class_method(x): # <----
            return x
    
        @commands.command(name='test')
        async def test(ctx, *args):
            # How can I access self.an_instance_property from here?
            print(ctx.bot.an_instance_property)   # <----
            return