Python开发Discord机器人出现TypeError: 'coroutine' object is not subscriptable报错如何修复
错误原因
- 核心问题是命名冲突:你编写的士兵训练计算函数名为
train,同时注册的Discord命令名也设置为train,导致命令函数内调用train()时,实际调用的是Discord框架生成的命令对象,而非你自己写的计算逻辑。调用命令对象会返回协程实例,你尝试对协程使用['key']下标取值,就触发了TypeError: 'coroutine' object is not subscriptable报错。运行日志里的RuntimeWarning: coroutine 'Command.__call__' was never awaited也印证了这一点。 - 次要问题:如果你的项目使用的是异步MongoDB驱动(如Motor,适配discord.py异步场景的标准选择),所有数据库操作(
find_one、find_one_and_update)都需要加await关键字,否则拿到的也是协程对象,无法正常读取/写入数据。 - 额外逻辑冗余:代码中重复多次查询同一条用户数据,还存在矛盾的条件判断(已判断用户存在后又判断用户不存在),会浪费数据库性能,也可能触发逻辑异常。
修复代码
1. 重命名计算函数,避免冲突
p_t1 = 1 p_t2 = 8 p_t3 = 20 # training potions of t1,t2,t3 train_pot = 0 # 函数名从train改为calc_train,避免和命令名冲突 def calc_train(troop_count, train_pot, tier, t1, t2, t3): if(tier == 1): if(troop_count*p_t1 > train_pot): # checks whether we have enough training costs for training t1 result = "Not enough training potions" return result else: train_pot = train_pot-troop_count*p_t1 # if yes train the tier 1 troops t1 += troop_count result = { 'training_train_pot': train_pot, 'tier1': t1, 'tier2': t2, 'tier3': t3 } return result elif(tier == 2): if(troop_count*p_t2 > train_pot): # checks whether we have enough training costs for training t2 result = "Not enough training potions" return result else: # if yes train the tier 2 troops train_pot = train_pot-troop_count*p_t2 t2 += troop_count result = { 'training_train_pot': train_pot, 'tier1': t1, 'tier2': t2, 'tier3': t3 } return result elif(tier == 3): # checks whether we have enough training costs for training t3 if(troop_count*p_t3 > train_pot): result = "Not enough training potions" return result else: # if yes train the tier 3 troops train_pot = train_pot-troop_count*p_t3 t3 += troop_count result = { 'training_train_pot': train_pot, 'tier1': t1, 'tier2': t2, 'tier3': t3 } return result else: # if we gave invalid tier print no such tier exist result = "No such tier troops exist" return result
2. 修正训练命令代码
@bot.command(name="train") # Training the soldiers # tier - troop tier to train, Amount - No. of troops to train async def training(ctx: commands.Context, tier: int = None, amount: int = None): ''' Used to train troops `?train <tier> <troops_amount>` Eg: ||?train 3 100||''' if tier is None or amount is None: await ctx.send("Give the argument correctly like `?train <tier> <troops_amount>`") return # 只查询一次用户数据,加await适配异步驱动 user_data = await user_info.find_one({'id': ctx.author.id}) if not user_data: await ctx.reply('Please start using `?start` command') return filtr = {'id': ctx.author.id} # 调用重命名后的计算函数 res = calc_train(amount, user_data['potions'], tier, user_data['t1'], user_data['t2'], user_data['t3']) if res == "Not enough training potions": await ctx.send(f'{ctx.author.mention}You dont have enough potions') elif res == "No such tier troops exist": await ctx.send(f'{ctx.author.mention}No such tier exists. Tiers available are 1-3') else: # 数据库更新操作加await await user_info.find_one_and_update(filtr, {'$set': { 't1': res['tier1'], 't2': res['tier2'], 't3': res['tier3'], 'potions': res['training_train_pot']}}) await ctx.send(f"{ctx.author.mention}You have successfully trained {amount} tier {tier} troops")
内容的提问来源于stack exchange,提问作者Daniel Jebarson K
相关产品推荐
相关产品推荐

