discord.py中self未定义报错,如何实现下拉菜单选分类显示命令文档字符串?
问题
我需要实现一个功能:通过Discord机器人的下拉菜单选择命令分类,展示该分类下所有命令的文档字符串。但运行代码时触发“self未定义”错误,代码如下:
class OptionView(discord.ui.View): @discord.ui.select(placeholder = "Option", min_values=1, max_values=1, options=[ discord.SelectOption(label=filename[:-3]) for filename in self.bot.get_cog() ]) async def select_callback(self, interaction:discord.Interaction,select:discord.ui.Select): embed = discord.Embed( title='Commands', colour=discord.Color.blue() ) self.disabled = True value = select.values[0] # command's category commands_list = [command.name for command in self.bot.get_cog(value).get_commands()] # Get command names in the category for command in commands_list: cmd = self.bot.get_command(command) docstring = cmd.callback.__doc__ or "No docstring" embed.add_field(name=command, value=docstring, inline=True) await interaction.response.send_message(embed=embed) await interaction.response.send_message(embed=embed,view=OptionView())
错误原因与修复方案
核心错误原因
装饰器@discord.ui.select是在类定义阶段执行的,此时类还没有被实例化,self这个实例对象根本不存在,所以在装饰器的options参数里直接用self.bot.get_cog()会触发“self未定义”错误。
修复步骤
- 将下拉菜单的选项初始化移到类的
__init__方法中,只有在实例化View时才能访问到self和bot实例。 - 给
OptionView的构造方法添加bot参数,确保View能获取到机器人实例。 - 修正回调函数里的逻辑错误:
- 循环内不要重复发送消息,应该先把所有字段添加到Embed后再统一发送。
- 重新创建
OptionView时要传入bot实例,否则新的View会缺少必要的机器人引用。 - 若要禁用下拉菜单,应该设置
select.disabled = True而非self.disabled = True(后者会禁用整个View)。
修正后的完整代码
class OptionView(discord.ui.View): def __init__(self, bot): super().__init__() self.bot = bot # 在__init__中初始化下拉菜单选项 cog_names = [cog.__class__.__name__ for cog in self.bot.cogs.values()] select_options = [discord.SelectOption(label=name) for name in cog_names] # 创建下拉菜单组件并添加到View self.select_menu = discord.ui.Select( placeholder="选择命令分类", min_values=1, max_values=1, options=select_options ) self.select_menu.callback = self.select_callback self.add_item(self.select_menu) async def select_callback(self, interaction: discord.Interaction, select: discord.ui.Select): embed = discord.Embed( title='命令列表', colour=discord.Color.blue() ) # 禁用当前下拉菜单 select.disabled = True value = select.values[0] # 获取选中的分类名称 # 获取该分类下的所有命令 cog = self.bot.get_cog(value) if not cog: await interaction.response.send_message("该分类不存在", ephemeral=True) return commands_list = cog.get_commands() for command in commands_list: docstring = command.callback.__doc__ or "无文档说明" embed.add_field(name=command.name, value=docstring, inline=True) # 发送Embed并更新View(禁用后的菜单) await interaction.response.send_message(embed=embed, view=self)
关键修改说明
- 把下拉菜单的创建逻辑移到
__init__,确保实例化时才能访问self.bot,避免类定义阶段的self未定义问题。 - 直接通过
self.bot.cogs.values()获取所有Cog实例,再提取名称,比原代码的get_cog()调用更准确(原代码get_cog()需要传入名称,这里应该是获取所有Cog的名称)。 - 修复了回调中重复发送消息的问题,改为统一发送完整的Embed。
- 增加了Cog不存在的判断,避免空引用错误。
- 禁用下拉菜单后直接使用当前View回复,不需要重新创建新的View实例(如果需要重新启用可以另行处理)。
内容的提问来源于stack exchange,提问作者克克KeJC
相关产品推荐
相关产品推荐

