You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python开发Discord机器人时无法向JSON文件追加保存触发词数据

问题现象

开发支持用户保存自定义聊天触发词的Discord机器人时,存储环节出现异常:先后执行!learn test1 pass、!learn test2 pass两条指令后,JSON文件仅保存1条触发词记录。

当前异常的JSON文件内容:

{
    "wordlist": {
        "word": "test1",
        "response": "('pass',)",
        "owner": "b4psa3"
    }
}

对应功能原实现代码:

@client.command()
async def learn(ctx, wordreceived, *wordresponse):
    try:
        with open("wordlist.p", "rb") as file:
            what_word_received = pickle.load(file)
    except FileNotFoundError:
        with open("wordlist.p", "wb") as file:
            what_word_received = list()
            pickle.dump(what_word_received, file)
    
    if wordreceived not in what_word_received:
        what_word_received.append(wordreceived)
        with open("wordlist.p", "wb") as file:
            pickle.dump(what_word_received, file)
        file_path = "./words.json"
        if os.path.isfile(file_path) == True:
            with open(file_path, "r", encoding='utf-8') as outfile:
                data = json.load(outfile)

            data['wordlist'].append({
                    "word": f"{wordreceived}",
                    "response": f"{wordresponse}",
                    "owner": f"{ctx.message.author.name}"
                })
                
            with open(file_path, 'a', encoding='utf-8') as outfile:
                json.dump(data, outfile, indent=2, ensure_ascii=False)
        else:
            data = {}
            data['wordlist'] = []
            data['wordlist'] = {
                    "word": f"{wordreceived}",
                    "response": f"{wordresponse}",
                    "owner": f"{ctx.message.author.name}"
                }
            with open(file_path, 'w', encoding='utf-8') as outfile:
                json.dump(data, outfile, indent=4, ensure_ascii=False)
    else:
        print(what_word_received)
        await ctx.send("This word is already exist")
故障原因

代码里存在3个直接导致存储异常的问题:

  • 首次初始化JSON结构错误:先给data['wordlist']赋值为空列表,紧接着直接将其覆盖为单个字典对象,导致wordlist不是预期的可追加多条记录的列表结构
  • JSON写入模式错误:文件已存在时使用'a'追加模式写入,JSON是结构化文本,直接在文件末尾追加新内容会生成非法格式的JSON文件,无法被正常解析
  • 逻辑顺序不合理:重复校验通过后才初始化/读取JSON数据,一旦JSON读写报错,pickle存储的索引和JSON实际存储内容会不一致,后续重复校验完全失效
修复代码
import os
import json
import pickle

@client.command()
async def learn(ctx, wordreceived, *wordresponse):
    pickle_path = "wordlist.p"
    json_path = "./words.json"

    # 加载已存触发词索引
    try:
        with open(pickle_path, "rb") as f:
            word_index = pickle.load(f)
    except FileNotFoundError:
        word_index = []

    # 先做重复校验
    if wordreceived in word_index:
        print(word_index)
        await ctx.send("This word is already exist")
        return

    # 更新pickle索引
    word_index.append(wordreceived)
    with open(pickle_path, "wb") as f:
        pickle.dump(word_index, f)

    # 读取已有JSON数据,兼容旧错误结构
    if os.path.exists(json_path):
        with open(json_path, "r", encoding="utf-8") as f:
            data = json.load(f)
        # 把之前错误存成单字典的结构转成列表
        if isinstance(data.get("wordlist"), dict):
            data["wordlist"] = [data["wordlist"]]
    else:
        data = {"wordlist": []}

    # 追加新触发词记录
    data["wordlist"].append({
        "word": wordreceived,
        "response": wordresponse,
        "owner": ctx.message.author.name
    })

    # 全量覆盖写入JSON,禁止用追加模式写结构化JSON
    with open(json_path, "w", encoding="utf-8") as f:
        json.dump(data, f, indent=4, ensure_ascii=False)
修复说明
  • 修正初始化逻辑:wordlist固定为列表类型,不再错误覆盖为单个字典
  • 统一JSON写入方式:所有场景都用'w'模式全量覆盖写入,避免追加模式生成非法JSON
  • 增加旧数据兼容:之前生成的错误结构的JSON文件不需要手动删除,代码会自动转换为正确的列表结构
  • 调整逻辑顺序:先做重复校验再执行写入操作,减少无效文件IO,避免两个存储文件数据不一致

内容的提问来源于stack exchange,提问作者b4psa3

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 10:15:30