首页 > 解决方案 > 我无法访问 Cog 内的类方法中的类参数

问题描述

我最近开始尝试使用 discord.py 进行机器人开发,并且一直在为某种情况而苦苦挣扎,在这种情况下,我在 Cogs 中使用了常规的类方法。这是一个示例,机器人应向“-hello”命令回复“hello there”:

import discord
from discord.ext import commands
import os
from dotenv import load_dotenv

load_dotenv()

class TestCog(commands.Cog):
    def __init__(self):
        super().__init__()
        self.testMessage = "hello there"
    
    @commands.command(name = 'hello')
    async def hello(self, ctx):
        await self.sayHello(ctx)

    @classmethod
    async def sayHello(self, ctx):
        await ctx.send(self.testMessage)

token = os.getenv("botToken")
intents = discord.Intents().all()
client = discord.Client(intents = intents)

bot = commands.Bot(command_prefix='-', intents=intents)

bot.add_cog(TestCog())

if __name__ == "__main__":
    bot.run(token)

如果我运行此代码,然后使用命令“-hello”,我会收到错误消息:

discord.ext.commands.errors.CommandInvokeError: Command raised an exception: AttributeError: type object 'TestCog' has no attribute 'testMessage'

我认为这是因为常规的类方法可能在 Cog 中不起作用,所以我也尝试这样写:

import discord
from discord.ext import commands
import os
from dotenv import load_dotenv

load_dotenv()

class TestBot(commands.Bot):
    def __init__(self, command_prefix, intents):
        super().__init__(command_prefix=command_prefix, intents=intents)

        self.testMessage = "hello there"
        self.add_cog(TestCog(self))

    @classmethod
    async def sayHello(self, ctx):
        await ctx.send(self.testMessage)

class TestCog(commands.Cog):
    def __init__(self, bot) -> None:
        super().__init__()
        self.bot = bot
    
    @commands.command(name = 'hello')
    async def hello(self, ctx):
        await self.bot.sayHello(ctx)


token = os.getenv("botToken")
intents = discord.Intents().all()
client = discord.Client(intents = intents)

bot = TestBot('-', intents)

if __name__ == "__main__":
    bot.run(token)

这也给出了同样的错误。但是,如果我不使用方法,并将其写为:

import discord
from discord.ext import commands
import os
from dotenv import load_dotenv

load_dotenv()

class TestBot(commands.Bot):
    def __init__(self, command_prefix, intents):
        super().__init__(command_prefix=command_prefix, intents=intents)

        self.add_cog(TestCog(self))

class TestCog(commands.Cog):
    def __init__(self, bot) -> None:
        super().__init__()
        self.testMessage = 'hello there'
    
    @commands.command(name = 'hello')
    async def hello(self, ctx):
        await ctx.send(self.testMessage)


token = os.getenv("botToken")
intents = discord.Intents().all()
client = discord.Client(intents = intents)

bot = TestBot('-', intents)

if __name__ == "__main__":
    bot.run(token)

它工作正常。它也适用于我不引用 self 的前两种情况,例如await ctx.send('hello there')代替 await ctx.send(self.testMessage). 但是,不能在命令中使用方法有点麻烦,所以我会绕过前两个场景吗?

标签: pythondiscorddiscord.py

解决方案


@classmethod装饰器不适用于在类中定义方法。这意味着当调用此方法时,我们将类作为第一个参数而不是该类的实例传递(就像我们通常对方法所做的那样)。这意味着您可以在该方法而不是特定实例中使用类及其属性。类中的普通函数是您要实际使用的类实例方法(普通/默认方法)

您的代码不起作用,因为 self 实际上是类本身而不是实例(因为它是类方法)。并且您无法访问实例变量,因为它不是实例。

要解决此问题,您应该删除 classmethod 装饰器以使其成为函数的普通方法

class TestCog(commands.Cog):
    def __init__(self):
        super().__init__()
        self.testMessage = "hello there"
    
    @commands.command(name = 'hello')
    async def hello(self, ctx):
        await self.sayHello(ctx)

    async def sayHello(self, ctx):
        await ctx.send(self.testMessage)

推荐阅读