Discord.py抽奖系统报错:async_generator无flatten属性,无法提及获奖者
Discord.py Cogs抽奖系统报错解决
问题描述
我是Discord.py新手,正在使用cogs开发抽奖系统。该系统需要机器人为抽奖消息添加反应,结束后根据点击反应的用户抽取获奖者,但抽奖结束时出现错误。
原代码
@commands.command() @commands.has_permissions(administrator=True) async def giveaway(self, ctx: commands.Context): await ctx.send("Let's start with this giveaway! Answer these questions within 15 seconds!") questions = ["Which channel should it be hosted in?", "What should be the duration of the giveaway? (s|m|h|d)", "What is the prize of the giveaway?"] answers = [] def check(m): return m.author == ctx.author and m.channel == ctx.channel for i in questions: await ctx.send(i) try: msg = await self.bot.wait_for('message', timeout=15.0, check=check) except asyncio.TimeoutError: await ctx.send('You didn\'t answer in time, please be quicker next time!') return else: answers.append(msg.content) try: c_id = int(answers[0][2:-1]) except: await ctx.send(f"You didn't mention a channel properly. Do it like this {ctx.channel.mention} next time.") return channel = self.bot.get_channel(c_id) time = convert(answers[1]) if time == -1: await ctx.send(f"You didn't answer the time with a proper unit. Use (s|m|h|d) next time!") return elif time == -2: await ctx.send(f"The time must be an integer. Please enter an integer next time") return prize = answers[2] await ctx.send(f"The Giveaway will be in {channel.mention} and will last {answers[1]}!") embed = discord.Embed(title = "Giveaway!", description = f"{prize}", color = ctx.author.color) embed.add_field(name = "Hosted by:", value = ctx.author.mention) embed.set_footer(text = f"Ends {answers[1]} from now!") my_msg = await channel.send(embed = embed) await my_msg.add_reaction("🎉") await asyncio.sleep(time) new_msg = await channel.fetch_message(my_msg.id) users = await new_msg.reactions[0].users().flatten() users.pop(users.index(self.bot.user)) winner = random.choice(users) await channel.send(f"Congratulations! {winner.mention} won {prize}!") def convert(time): pos = ["s","m","h","d"] time_dict = {"s" : 1, "m" : 60, "h" : 3600 , "d" : 3600*24} unit = time[-1] if unit not in pos: return -1 try: val = int(time[:-1]) except: return -2 return val * time_dict[unit]
报错信息
Traceback (most recent call last): File "C:\Users\Human\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\discord\ext\commands\core.py", line 229, in wrapped ret = await coro(*args, **kwargs) File "c:\Users\Human\Documents\TestBot\cogs\giveaways.py", line 78, in giveaway users = await new_msg.reactions[0].users().flatten() AttributeError: 'async_generator' object has no attribute 'flatten' The above exception was the direct cause of the following exception: Traceback (most recent call last): File "C:\Users\Human\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\discord\ext\commands\bot.py", line 1349, in invoke await ctx.command.invoke(ctx) File "C:\Users\Human\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\discord\ext\commands\core.py", line 1023, in invoke await injected(*ctx.args, **ctx.kwargs) # type: ignore File "C:\Users\Human\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\discord\ext\commands\core.py", line 238, in wrapped raise CommandInvokeError(exc) from exc discord.ext.commands.errors.CommandInvokeError: Command raised an exception: AttributeError: 'async_generator' object has no attribute 'flatten'
报错原因
Discord.py v2.x版本对API进行了更新,Reaction.users()方法不再返回可迭代的用户集合,而是返回异步生成器,因此原来调用的.flatten()方法不再存在,导致报错。
解决办法
修改获取反应用户的代码,通过异步遍历生成器来收集用户,同时过滤掉机器人自身:
替换代码段
将原代码中的:
users = await new_msg.reactions[0].users().flatten() users.pop(users.index(self.bot.user))
替换为以下两种写法之一:
写法一:异步循环收集
users = [] async for user in new_msg.reactions[0].users(): if user != self.bot.user: users.append(user)
写法二:异步列表推导式(更简洁)
users = [user async for user in new_msg.reactions[0].users() if user != self.bot.user]
额外优化
为了避免没有用户参与抽奖时random.choice()报错,可以添加判断逻辑:
if not users: await channel.send("没有用户参与本次抽奖,无法选出获奖者!") return winner = random.choice(users)
内容的提问来源于stack exchange,提问作者user20058229
相关产品推荐
相关产品推荐

