Python开发Discord bot触发IndexError列表索引越界报错求助
Discord机器人start命令触发IndexError问题
以下是问题涉及的原始代码:
@bot.command() async def start(ctx): edit = [] with open("wallet.json", "w") as file: for obj in file: dict = json.load(obj) edit.append(dict) userid = [] for player in edit: userid.append(str(player["id"])) user = str(ctx.author.id) if userid.count(user) > 0: await ctx.reply("You already have an account") else: embed = nextcord.Embed(title = "Welcome to the Kingdoms of Sulphae!", description = "Sulphae is a place where people can grind for resources, conquer other factions, and become the greatest king to ever exist! Enjoy your stay!") embed.set_footer(text = "Made by Energia360, a really pog dude who decided to dedicate his summer break to making a Discord bot") await ctx.send(embed = embed) userid.append(user) edit[userid.index(user)]["id"] = user edit[userid.index(user)]["gold"] = 0 edit[userid.index(user)]["fyre"] = 0 edit[userid.index(user)]["faction"] = None json.dump(edit, file)
问题现象
- 使用Python开发Discord机器人时运行上述代码,当前
wallet.json文件为空,代码执行到edit[userid.index(user)]["id"] = user位置时触发IndexError: list index out of range报错。
调试记录
- 第一次调试:添加
print()语句输出userid.index(user)的返回值为0,该索引数值本身不存在超出范围的问题,初步推测问题出在JSON字典键访问环节。 - 第二次调试:将
userid.index(user)的返回值提前存入独立变量再调用,报错依旧存在,进一步怀疑是键"id"的访问操作触发错误。
错误根因
索引越界和字典键访问没有任何关系,是三个基础逻辑错误导致的:
- 文件打开模式错误:读取
wallet.json时使用了"w"(写入覆盖模式)打开文件,该模式会直接清空文件内所有原有内容,后续遍历文件读取JSON数据的逻辑完全不会执行,edit列表从初始化后就一直是空列表。 - 新用户数据未追加到edit列表:判断用户不存在时,只把新用户ID追加到了
userid列表,根本没有给edit列表添加对应的新用户字典。此时userid长度比edit多1,拿到新用户ID在userid里的索引0去访问长度为0的空列表edit,必然触发索引越界。 - 文件作用域错误:
json.dump(edit, file)写在with open()的代码块外面,此时文件对象已经被自动关闭,就算前面逻辑跑通,写入JSON的步骤也会报错。
修复方案
- 读取JSON文件时使用
"r"(只读)模式,文件不存在或者内容为空时,直接初始化edit为空列表即可。 - 新用户注册时,先构造好新用户的字典数据,追加到
edit列表后再做后续处理。 - 写入JSON时重新以
"w"模式打开文件,把更新后的edit列表写入,不要在with块外操作已关闭的文件对象。 - 不要用
dict做变量名,会覆盖Python内置的dict类型。
修复后的参考代码:
import os import json import nextcord @bot.command() async def start(ctx): edit = [] # 钱包文件存在且有内容时才读取 if os.path.exists("wallet.json") and os.path.getsize("wallet.json") > 0: with open("wallet.json", "r", encoding="utf-8") as file: edit = json.load(file) userid = [str(player["id"]) for player in edit] user = str(ctx.author.id) if user in userid: await ctx.reply("You already have an account") return # 新用户直接构造数据追加到edit列表 new_user = { "id": user, "gold": 0, "fyre": 0, "faction": None } edit.append(new_user) embed = nextcord.Embed( title = "Welcome to the Kingdoms of Sulphae!", description = "Sulphae is a place where people can grind for resources, conquer other factions, and become the greatest king to ever exist! Enjoy your stay!" ) embed.set_footer(text = "Made by Energia360, a really pog dude who decided to dedicate his summer break to making a Discord bot") await ctx.send(embed = embed) # 写入更新后的数据 with open("wallet.json", "w", encoding="utf-8") as file: json.dump(edit, file, indent=2, ensure_ascii=False)
额外优化点:用
user in userid替代userid.count(user) > 0判断用户是否存在,执行效率更高。
内容的提问来源于stack exchange,提问作者Energia360
相关产品推荐
相关产品推荐

