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" } ] }
错误原因分析
- 覆盖初始课程数据:读取
educations.json时,用data = json.load(file)覆盖了之前从courses.json加载的课程数据变量,导致原有课程记录全部丢失,每次都是基于教育数据对象添加课程,完全没用到历史课程数据。 - 文件写入方式错误:使用
'a'追加模式时,每次只写入课程列表courses,而非完整的{"Courses": [...]}结构,导致文件中出现多个独立数组,而非合法的统一JSON对象。 - 变量命名冲突:函数名
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
相关产品推荐
相关产品推荐

