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

Python通讯录项目中如何避免JSON文件被覆盖?

解决通讯录管理器JSON数据覆盖及加载失效问题

问题根源分析

  • 数据加载未关联到通讯录实例:调用load_file后未将读取的JSON数据转为Contact对象并添加到ContactBook的联系人列表,导致每次启动都是空通讯录,退出时新数据直接覆盖原有数据。
  • Contact类序列化结构冗余:__str__方法返回嵌套的contact_info结构,导致最终保存的JSON出现不必要的层级嵌套。
  • ContactBook的contacts为类属性:所有ContactBook实例共享同一个联系人列表,易引发数据混乱。
  • 删除操作存在潜在bug:搜索不到联系人时search_contact返回提示字符串,直接传入remove_contact会触发报错。

修复步骤及代码修改

1. 修复数据加载逻辑

修改main函数,将加载的JSON数据转化为Contact对象并初始化通讯录:

from colorama import Fore, Style
from LoadAndSave import load_file, save_file
from ContactBook import ContactBook
from Contact import Contact

DATA_FILE = "contactbook.json"

def menu():
    print(Fore.RED + "Welcome to Contacts Manager v2.0.0!" + Style.RESET_ALL)
    print(Fore.LIGHTCYAN_EX + "Please enter your selection according to the menu." + Style.RESET_ALL)
    print("a - Add a contact")
    print("r - Remove a contact")
    print("s - Search for a contact")
    print("p - Print a list of all contacts")
    print("x - Exit")
    user_selection = input(Fore.GREEN + "Your selection: " + Style.RESET_ALL)
    return user_selection

def main():
    # 加载数据并转化为Contact对象
    loaded_data = load_file(DATA_FILE)
    contactbook = ContactBook()
    
    # 兼容现有JSON结构,将数据转为Contact实例
    for item in loaded_data:
        if isinstance(item, dict) and "contact_info" in item:
            for contact_data in item["contact_info"]:
                contactbook.add_contact(contact_data["name"], contact_data["tel"])
        elif isinstance(item, dict) and "name" in item and "tel" in item:
            contactbook.add_contact(item["name"], item["tel"])
    
    user_selection = ""
    while user_selection != "x":
        user_selection = menu()
        if user_selection == "a":
            contactbook.add_contact(input("Please enter contact's name: "), int(input("Please enter contact's number: ")))
        if user_selection == "r":
            target_contact = contactbook.search_contact(input("Contact's Name? "))
            # 仅找到联系人时执行删除
            if isinstance(target_contact, Contact):
                contactbook.remove_contact(target_contact)
            else:
                print(target_contact)
        if user_selection == "s": 
            result = contactbook.search_contact(input("Contact's name?"))
            print(result)
            print(Fore.GREEN + "Success!" + Style.RESET_ALL)
        if user_selection == "p":
            print(contactbook)
            print(Fore.GREEN + "Success!" + Style.RESET_ALL)
    print(Fore.MAGENTA + "Thank you for using my software. Bye!")
    save_file(contactbook.make_contact_json(), DATA_FILE)
            

if __name__ == "__main__":
    main()

2. 优化Contact类结构

简化序列化逻辑,新增to_dict方法避免字符串解析:

import json

class Contact:
    def __init__(self, name="", tel=0):
        self.name = name
        self.tel = tel

    def __str__(self):
        return json.dumps({"name": self.name, "tel": self.tel})
    
    def to_dict(self):
        return {"name": self.name, "tel": self.tel}

3. 修复ContactBook类属性及方法

将contacts改为实例属性,优化序列化方法:

from colorama import Fore, Style, Back
from Contact import Contact
import json

class ContactBook:
    def __init__(self):
        # 改为实例属性,每个通讯录实例拥有独立列表
        self.contacts = []

    def add_contact(self, name="", tel=0):
        self.contacts.append(Contact(name, tel))
        print(Fore.GREEN + "Success!" + Style.RESET_ALL)

    def remove_contact(self, contact):
        if isinstance(contact, Contact):
            self.contacts.remove(contact)
            print(Fore.RED + "Removed.\n" + Style.RESET_ALL)

    def search_contact(self, contact_name):
        for contact in self.contacts:
            if contact.name == contact_name:
                return contact
        return Back.RED + "\nThere is no contact with that name." + Style.RESET_ALL + "\n"
    
    def make_contact_json(self):
        # 直接使用to_dict生成序列化数据
        return [contact.to_dict() for contact in self.contacts]

    def __str__(self) -> str:
        result = ""
        for contact in self.contacts:
            result += str(contact) + "\n"
        return result

4. 优化后JSON结构

修复后保存的JSON会更简洁,避免嵌套冗余:

[
    {
        "name": "sdfgh",
        "tel": 654321
    },
    {
        "name": "new_contact",
        "tel": 123456
    }
]

关键修复点总结

  • 确保加载的数据被正确转为Contact对象并添加到通讯录实例
  • 将类属性改为实例属性,避免跨实例数据共享
  • 简化序列化结构,减少不必要的层级嵌套
  • 增加删除操作的类型判断,避免无效输入报错

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 18:16:04