Discord.py v2.0按钮交互调用interaction属性触发AttributeError
问题描述
使用Discord.py 2.0开发带按钮功能的Discord机器人时,调用interaction.user、interaction.response等任意interaction相关属性,都会触发错误:AttributeError: 'Button' object has no attribute 'user'。
报错回溯
Traceback (most recent call last): File "C:\Users\parke\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0\LocalCache\local-packages\Python39\site-packages\discord\ui\view.py", line 423, in _scheduled_task await item.callback(interaction) File "C:\Users\parke\Documents\GitHub\thedrew\goblins\goblin.py", line 29, in menu1 print(f'added {interaction.user.name} to party') AttributeError: 'Button' object has no attribute 'user'
完整代码
import discord from discord.ext import commands client = commands.Bot(command_prefix='g!', intents=discord.Intents.all()) inProgress = False combat = [] turn = False class Player: hp = 100 atk = 100 player1 = Player() player2 = Player() @client.event async def on_ready(): print('ready to battle') class Invite(discord.ui.View): def __init__(self): super().__init__() @discord.ui.button(label="Accept", style=discord.ButtonStyle.green) async def menu1(self, button: discord.ui.Button, interaction: discord.Interaction): print(f'added {interaction.user.name} to party') combat.append(interaction.user) @discord.ui.button(label="Decline", style=discord.ButtonStyle.red) async def menu2(self, button: discord.ui.Button, interaction: discord.Interaction): print(f'{interaction.user} declined invitation') combat.clear() @client.command() async def invite(ctx, member: discord.Member): em = discord.Embed(title=f'Goblin Combat Invite', description=f"You've been invited to Goblin Combat by {ctx.author.name}!") view = Invite() await ctx.channel.send(embed=em, view=view) print(f'Invited {member.name} to Goblin Combat!') @client.command() async def start(ctx): global inProgress if ctx.author in combat and inProgress == False: await gameLoop(ctx) elif inProgress == True: await ctx.channel.send('Someone has already been challenged to Goblin Combat. Sit back and enjoy the show!') elif ctx.author not in combat: await ctx.channel.send('You have not been invited to Goblin Combat. Sucks to be you!') class Actions(discord.ui.View): def __init__(self): super().__init__() @discord.ui.button(label="Attack", style=discord.ButtonStyle.red) async def menu1(self, button: discord.ui.Button, interaction: discord.Interaction): print(f'did {player1.atk} damage') await interaction.message.channel.send(f'{interaction.user.name} attacked for {player1.atk} damage!') @discord.ui.button(label="Use", style=discord.ButtonStyle.green) async def menu2(self, button: discord.ui.Button, interaction: discord.Interaction): await interaction.response.edit_message(content="Used Goblin Spell") async def gameLoop(ctx): global inProgress em = discord.Embed(title=f"Goblin Combat", description=f'{combat[0].name} v {combat[1].name}', color=discord.colour.Color.green()) em.set_image(url="https://cdn.discordapp.com/attachments/945053385953005648/1000583183017975878/screen.png") em.set_footer(text=f"{combat[int(turn)].name}'s Turn") view = Actions() await ctx.channel.send(embed=em, view=view) inProgress = True client.run(token)
解决方案
这个错误的核心是按钮回调函数的参数顺序搞反了。在Discord.py 2.0中,按钮回调的正确参数顺序是:interaction: discord.Interaction在前,button: discord.ui.Button在后。
你当前的回调函数写法把参数顺序写反了,导致代码里的interaction变量实际接收的是Button实例,自然不存在user属性。只需修正所有按钮回调的参数顺序即可:
修正Invite类的按钮回调
@discord.ui.button(label="Accept", style=discord.ButtonStyle.green) async def menu1(self, interaction: discord.Interaction, button: discord.ui.Button): print(f'added {interaction.user.name} to party') combat.append(interaction.user) @discord.ui.button(label="Decline", style=discord.ButtonStyle.red) async def menu2(self, interaction: discord.Interaction, button: discord.ui.Button): print(f'{interaction.user} declined invitation') combat.clear()
修正Actions类的按钮回调
@discord.ui.button(label="Attack", style=discord.ButtonStyle.red) async def menu1(self, interaction: discord.Interaction, button: discord.ui.Button): print(f'did {player1.atk} damage') await interaction.message.channel.send(f'{interaction.user.name} attacked for {player1.atk} damage!') @discord.ui.button(label="Use", style=discord.ButtonStyle.green) async def menu2(self, interaction: discord.Interaction, button: discord.ui.Button): await interaction.response.edit_message(content="Used Goblin Spell")
内容的提问来源于stack exchange,提问作者wooshdude
相关产品推荐
相关产品推荐

