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

Python课程数据写入JSON文件格式错误及数据覆盖问题排查

问题描述

我尝试添加课程数据(输入课程ID、名称、起止日期、学分),加载educations.json文件选择关联的教育项目,将教育名称加入课程后保存到courses.json。但最终文件输出格式不符合预期:

  • 每次添加的课程以独立数组形式存在,而非统一的{"Courses": [所有课程]}结构
  • 原课程数据被覆盖

我的代码

# import packages
import json
from datetime import datetime

def courses():
    # Json File Name
    filename = 'courses.json'
    
    # Read Json file and load content in data variable
    try:
        with open("courses.json", "r") as file:
            # load content
            content = file.read()
            # if json file has content save in data variable
            if content:
                data = json.loads(content)
            # else load empty json object in data variable
            else:
                data = json.loads('{"Courses": [] }')
    # exception handling
    except FileNotFoundError:
        data = json.loads('{"Courses": [] }')
    except json.decoder.JSONDecodeError:
        data = json.loads('{"Courses": [] }')

    # While User wants to add more records
    while True:
        # input course id
        courseId = input("Enter course id: ")
        # input course name
        course_name = input("Enter course name: ")
        
        # input start date
        start_input_date = input("Enter the start date in the format (yyyy-mm-dd): ")
        start_date = datetime.strptime(start_input_date, "%Y-%m-%d")
        start_date_str = start_date.strftime("%Y-%m-%d")

        # input end date
        end_input_date = input("Enter the end date in the format (yyyy-mm-dd): ")
        end_date = datetime.strptime(end_input_date, "%Y-%m-%d")
        end_date_str = end_date.strftime("%Y-%m-%d")
        
        # input course credits
        credits = int(input("Enter amount of course credits: "))
        
        # Load the JSON file
        with open("educations.json", "r") as file:
            # Load the JSON data
            data = json.load(file)
            
            # Try to convert the loaded JSON data into a list
            try:
                educations = list(data["Educations"])
            # If the "Educations" key does not exist in the "data" dictionary, assign an empty list to the "educations" variable
            except KeyError:
                educations = []
        # Get the number of educations
        num_educations = len(educations)
        print("Number of Educations:", num_educations)

        # Enumerate through the list of educations and print the index and education name
        for index, education in enumerate(educations, start=1):
            print(index, education["education_name"])

        # Get the index of the education to be chosen
        chosen_index = int(input("Enter the index of the education you want to choose: "))

        # Check if the chosen index is within the range
        if chosen_index > 0 and chosen_index <= num_educations:
            # Print the chosen education
            print("Chosen Education: ", educations[chosen_index - 1])
        else:
            print("Invalid index. Please try again.")
            
        education_name = educations[chosen_index - 1]["education_name"]
        entry = {'courseId': courseId, 'course_name': course_name, 'start_date': start_date_str, 'end_date': end_date_str, 'credits': credits, 'education_name': education_name}
        
        # Try to append new row in the "Courses" key of the "data" dictionary
        try:
            data["Courses"].append(entry)
        # If the "Courses" key does not exist in the "data" dictionary, create the "Courses" key with an empty list as its value
        except KeyError:
            data["Courses"]=[]
            data["Courses"].append(entry)
        # Store all courses in a list
        courses = data["Courses"]
        
        print("All courses: ")
        for index, course in enumerate(courses):
            print(f"{index + 1}. Course:")
            for key, value in course.items():
                print(f"\t{key}: {value}")
        
        # append data in json file
        with open(filename, 'a') as outfile:
            json.dump(courses, outfile, indent=4) # using indent to make json more readable
            outfile.write('\n')
        print("Course added to file successfully!\n")
        # ask users for inserting more records or exit program
        add_more = input("Do you want to add more courses? (y/n)")
        if add_more.lower() == 'n':
            break
    
courses()

educations.json内容

{
    "Educations": [
        {
            "education_name": "itsak",
            "start_date": "2022-08-22",
            "end_date": "2024-05-20",
            "education_id": "itsak2023"
        },
        {
            "education_name": "Jamstack",
            "start_date": "2023-08-22",
            "end_date": "2025-05-20",
            "education_id": "Jamst2023"
        },
        {
            "education_name": "Backend developer",
            "start_date": "2023-08-22",
            "end_date": "2025-05-20",
            "education_id": "Backe2023"
        }
    ]
}

当前输出

[
    {
        "courseId": "itstrapi",
        "course_name": "Strapi",
        "start_date": "2022-08-22",
        "end_date": "2022-09-21",
        "credits": 45,
        "education_name": "Backend developer"
    }
]
[
    {
        "courseId": "itgatsby",
        "course_name": "Gatsby",
        "start_date": "2022-09-22",
        "end_date": "2022-10-21",
        "credits": 30,
        "education_name": "Jamstack"
    }
]

期望输出

{
    "Courses": [
    {
        "courseId": "itstrapi",
        "course_name": "Strapi",
        "start_date": "2022-08-22",
        "end_date": "2022-09-21",
        "credits": 45,
        "education_name": "Backend developer"
    },
    {
        "courseId": "itgatsby",
        "course_name": "Gatsby",
        "start_date": "2022-09-22",
        "end_date": "2022-10-21",
        "credits": 30,
        "education_name": "Jamstack"
    }
]
}

错误原因分析
  1. 覆盖初始课程数据:读取educations.json时,用data = json.load(file)覆盖了之前从courses.json加载的课程数据变量,导致原有课程记录全部丢失,每次都是基于教育数据对象添加课程,完全没用到历史课程数据。
  2. 文件写入方式错误:使用'a'追加模式时,每次只写入课程列表courses,而非完整的{"Courses": [...]}结构,导致文件中出现多个独立数组,而非合法的统一JSON对象。
  3. 变量命名冲突:函数名courses和内部存储课程列表的变量courses重名,可能引发逻辑异常。

修正后的代码
import json
from datetime import datetime

def manage_courses():
    filename = 'courses.json'
    
    # 初始化课程数据
    try:
        with open(filename, "r") as file:
            content = file.read()
            if content:
                course_data = json.loads(content)
            else:
                course_data = {"Courses": []}
    except FileNotFoundError:
        course_data = {"Courses": []}
    except json.decoder.JSONDecodeError:
        course_data = {"Courses": []}

    while True:
        # 输入课程信息
        courseId = input("Enter course id: ")
        course_name = input("Enter course name: ")
        
        # 处理开始日期(增加格式验证)
        while True:
            start_input_date = input("Enter the start date in the format (yyyy-mm-dd): ")
            try:
                start_date = datetime.strptime(start_input_date, "%Y-%m-%d")
                start_date_str = start_date.strftime("%Y-%m-%d")
                break
            except ValueError:
                print("日期格式错误,请重新输入。")
        
        # 处理结束日期(增加格式验证)
        while True:
            end_input_date = input("Enter the end date in the format (yyyy-mm-dd): ")
            try:
                end_date = datetime.strptime(end_input_date, "%Y-%m-%d")
                end_date_str = end_date.strftime("%Y-%m-%d")
                break
            except ValueError:
                print("日期格式错误,请重新输入。")
        
        credits = int(input("Enter amount of course credits: "))
        
        # 加载教育项目数据(使用独立变量避免覆盖课程数据)
        with open("educations.json", "r") as file:
            education_data = json.load(file)
            educations = education_data.get("Educations", [])
        
        num_educations = len(educations)
        print("教育项目数量:", num_educations)
        for index, education in enumerate(educations, start=1):
            print(index, education["education_name"])

        # 选择教育项目(增加输入合法性验证)
        while True:
            try:
                chosen_index = int(input("请选择教育项目的序号: "))
                if 0 < chosen_index <= num_educations:
                    break
                else:
                    print("序号无效,请重新输入。")
            except ValueError:
                print("请输入有效的数字序号。")
        
        education_name = educations[chosen_index - 1]["education_name"]
        entry = {
            'courseId': courseId,
            'course_name': course_name,
            'start_date': start_date_str,
            'end_date': end_date_str,
            'credits': credits,
            'education_name': education_name
        }
        
        # 添加课程到历史数据中
        course_data["Courses"].append(entry)
        
        # 打印当前所有课程
        print("所有课程: ")
        for index, course in enumerate(course_data["Courses"]):
            print(f"{index + 1}. 课程:")
            for key, value in course.items():
                print(f"\t{key}: {value}")
        
        # 写入完整的JSON结构到文件(覆盖模式保证格式合法)
        with open(filename, 'w') as outfile:
            json.dump(course_data, outfile, indent=4)
        print("课程已成功保存到文件!\n")
        
        add_more = input("是否继续添加课程?(y/n)")
        if add_more.lower() == 'n':
            break

manage_courses()
修正说明
  • 避免数据覆盖:将教育数据加载到独立变量education_data中,不再覆盖从courses.json读取的course_data,确保历史课程记录被保留。
  • 正确写入文件:使用'w'模式覆盖写入完整的course_data对象(即{"Courses": [...]}结构),保证文件始终是合法的JSON格式。
  • 修复变量冲突:将函数名改为manage_courses,避免和内部变量重名。
  • 增强输入验证:对日期输入和选择序号增加循环验证,避免非法输入导致程序崩溃。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 06:05:55