数据分析笔记13:Python 名片管理系统-练习案例

项目需求分析

功能需求

名片管理系统需实现以下功能:

  • 显示菜单:展示系统可用功能。
  • 新建名片:添加新的名片信息。
  • 显示全部名片:查看所有已存储的名片。
  • 查询名片:根据姓名搜索特定名片。
  • 删除名片:删除查询到的名片。
  • 退出系统:退出程序运行。

数据存储方案

存储结构设计:

# 使用列表作为容器
card_list = [
    {  # 第一张名片(字典)
        "name_key": "张伟",
        "phone_key": "13912345678",
        "wechat_key": "zhangwei123",
        "email_key": "zhangwei@example.com"
    },
    {  # 第二张名片(字典)
        "name_key": "李娜",
        "phone_key": "15887654321",
        "wechat_key": "lina456",
        "email_key": "lina@example.com"
    }
]

设计思路:

  • 字典:存储单张名片的所有信息(键值对形式)。
  • 列表:作为容器,存储所有名片字典。
  • 临时存储:数据仅在程序运行期间存在于内存中。

重要提醒:本节课的数据是临时存储,程序关闭后数据会丢失。下节课将学习如何将数据永久保存到文件。

代码架构设计

函数式编程思维

为什么使用函数?
当系统有多个功能时,每个功能应封装成独立的函数。
优势:

  • 代码结构清晰,易于维护。
  • 功能模块化,职责分明。
  • 便于调试和扩展。
  • 提高代码复用性。

函数设计原则

原则 说明 示例
单一职责 每个函数只做一件事 show_menu() 只负责显示菜单
命名清晰 函数名清楚表达功能 add_card() 表示添加名片
参数合理 需要什么数据就传什么参数 delete_card(dict) 传入要删除的字典
有返回值 需要结果就返回,不需要则省略 查询函数可以返回查询结果

主函数(控制中心)

主函数 run() 的作用:

  • 作为程序的控制中心。
  • 协调各个功能函数的调用。
  • 处理用户输入和选择逻辑。
def run():
    """主函数 - 程序的控制中心"""
    while True:  # 死循环,持续运行
        show_menu()  # 显示菜单
        action = input("请选择操作功能:")
        print(f"您选择的操作是:{action}")
        
        # 根据用户选择调用对应函数
        if action in ["1", "2", "3"]:
            if action == "1":
                add_card()
            elif action == "2":
                show_all()
            elif action == "3":
                search_card()
        elif action == "0":
            print("欢迎再次使用名片管理系统")
            break  # 退出循环
        else:
            print("输入错误,请重新选择")

# 程序入口:只需调用主函数
run()

死循环与退出机制
死循环 while True:

  • 让程序持续运行,不会自动退出。
  • 用户可以连续进行多次操作。

退出机制 break:

  • 当用户输入 0 时触发。
  • 使用 break 跳出循环。
  • 程序优雅退出。

功能函数详解

显示菜单 show_menu()

功能:展示系统可用功能列表。

def show_menu():
    """显示菜单"""
    print("*" * 50)
    print("欢迎使用名片管理系统 V1.0")
    print("")
    print("1. 新建名片")
    print("2. 显示全部")
    print("3. 查询名片")
    print("")
    print("0. 退出系统")
    print("*" * 50)

设计要点:

  • 使用分隔线美化界面。
  • 功能编号清晰(1、2、3、0)。
  • 空行增加可读性。

新建名片 add_card()

功能:收集用户输入的名片信息,保存到列表中。

# 创建全局容器(列表)
card_list = []

def add_card():
    """新建名片"""
    print("*" * 50)
    print("功能:新建名片")
    
    # 1. 收集名片信息
    name = input("请输入名字:")
    phone = input("请输入电话:")
    wechat = input("请输入微信:")
    email = input("请输入email:")
    
    # 2. 创建字典存储名片信息
    card_dict = {
        "name_key": name,
        "phone_key": phone,
        "wechat_key": wechat,
        "email_key": email
    }
    
    # 3. 将字典追加到列表
    card_list.append(card_dict)
    
    # 4. 打印确认信息
    print(card_list)
    print(f"成功添加 {name} 的名片")

执行流程:

  1. 收集信息 → 使用 input() 获取用户输入。
  2. 构建字典 → 使用键值对组织数据。
  3. 追加到列表 → 使用 append() 添加到容器。
  4. 反馈确认 → 打印成功信息。

关键技术点
字典的创建:

card_dict = {
    "name_key": name,      # 键:值
    "phone_key": phone,
    "wechat_key": wechat,
    "email_key": email
}

列表的追加:

card_list.append(card_dict)  # 将字典添加到列表末尾

数据结构演变:
输入 → 变量 → 字典 → 列表
name name {"name_key": name} [字典1, 字典2, ...]

显示全部名片 show_all()

功能:遍历列表,格式化显示所有名片信息。

def show_all():
    """显示所有名片"""
    print("*" * 50)
    print("功能:显示全部名片")
    print("")
    
    # 判断是否有名片记录
    if len(card_list) == 0:
        print("⚠️ 没有任何名片记录!!!")
        return  # 终止函数
    
    # 打印表头
    print(f"姓名\t\t\t\t电话\t\t\t\t微信\t\t\t\t邮箱\t\t\t\t")
    print("=" * 50)
    
    # 遍历列表,打印每张名片
    for d in card_list:
        print(f"{d['name_key']}\t\t\t{d['phone_key']}\t\t\t{d['wechat_key']}\t\t\t{d['email_key']}")

执行流程图:
开始

判断列表是否为空?
↓ 是
打印“没有记录”

return(终止)

↓ 否
打印表头

遍历列表

逐个打印名片信息

结束

关键技术点

  1. 空值判断:
if len(card_list) == 0:
    print("没有任何名片记录")
    return  # 立即终止函数

为什么判断?

  • 避免空列表遍历时出错。
  • 提供友好的用户提示。
  • 提前终止,节省资源。
  1. return 的妙用:
return  # 不返回任何值,仅终止函数

作用:

  • 遇到 return 立即退出函数。
  • 后面的代码不再执行。
  • 回到调用函数的地方。
  1. 格式化输出
    使用 \t 制表符对齐:
print(f"姓名\t\t\t\t电话\t\t\t\t微信\t\t\t\t邮箱")

使用 f-string 取字典值:

print(f"{d['name_key']}\t\t\t{d['phone_key']}")
  1. for 循环遍历:
for d in card_list:
    # d 是当前遍历到的字典
    print(d['name_key'])  # 通过键名取值

遍历过程: 第1次循环:d = {"name_key": "张伟", ...}
第2次循环:d = {"name_key": "李娜", ...}
第3次循环:d = {"name_key": "王芳", ...}
...

查询名片 search_card()

功能:根据姓名查询名片,找到后可选择删除。

def search_card():
    """查询名片"""
    # 1. 输入要查询的姓名
    find_name = input("请输入要搜索的姓名:")
    
    # 2. 遍历列表查询
    for d in card_list:
        if find_name == d["name_key"]:
            # 找到了!打印表头
            print("姓名\t\t\t\t电话\t\t\t\t微信\t\t\t\t邮箱\t\t\t\t")
            print("-" * 40)
            
            # 打印名片信息
            print(f"{d['name_key']}\t\t\t{d['phone_key']}\t\t\t{d['wechat_key']}\t\t\t{d['email_key']}")
            print("-" * 40)
            
            # 调用删除函数(传入字典)
            delete_card(d)
            break  # 找到后退出循环
    else:
        # 遍历完都没找到
        print(f"没有找到 {find_name} 的名片!")

执行流程:
输入要查询的姓名

遍历列表中的每个字典

当前字典的 name_key == 输入的姓名?
↓ 是
打印该名片信息

调用删除函数

break 退出循环

↓ 否
继续下一个字典

遍历结束仍未找到?

打印“没有找到”

关键技术点

  1. for...else 语法:
for d in card_list:
    if 条件:
        # 找到了
        break
else:
    # 遍历完都没找到才执行
    print("没有找到")

理解要点:

  • else 属于 for 循环,不属于 if。
  • 只有正常遍历完(没有 break)才执行 else。
  • 如果 break 退出,则不执行 else。
  1. 函数嵌套调用:
delete_card(d)  # 在查询函数中调用删除函数

调用流程:
search_card() 执行中
↓ 找到名片
暂停 search_card()

跳转到 delete_card()
↓ 执行完毕
返回 search_card()

break 退出循环

search_card() 结束

  1. 参数传递:
delete_card(d)  # d 是实参(实际的字典)

数据传递:
d = {"name_key": "张伟", ...} # 实参
↓ 传递
delete_card(find_dict) # 形参接收

删除名片 delete_card()

功能:接收字典参数,提供删除或返回选项。

def delete_card(find_dict):
    """删除名片"""
    # 打印要删除的名片信息
    print(find_dict)
    
    # 询问用户操作
    action_str = input("请选择要执行的操作:\n1.删除\n0.返回上级菜单\n")
    
    if action_str == "1":
        # 从列表中移除该字典
        card_list.remove(find_dict)
        print("删除成功")
    # 如果选择 0 或其他,函数自然结束,返回上级

关键技术点

  1. 形参与实参:
    实参(实际参数):
    search_card() 中:
    delete_card(d) # d 是实参,传递实际数据

形参(形式参数):
def delete_card(find_dict): # find_dict 是形参,接收数据

理解要点:

  • 形参和实参的名称可以不同。
  • 形参只是一个“占位符”,接收传入的数据。
  • 实参是真实存在的数据。
  • 数量必须匹配,名称不要求一致。
  1. remove() 方法:
card_list.remove(find_dict)  # 从列表中移除指定元素

工作原理:

  • 在列表中查找该字典。
  • 找到后将其移除。
  • 列表长度减1。

示例:

删除前

card_list = [{"name": "张伟"}, {"name": "李娜"}]

执行删除

card_list.remove({"name": "张伟"})

删除后

card_list = [{"name": "李娜"}]

  1. 函数的自然结束:
if action_str == "1":
    # 删除操作
    card_list.remove(find_dict)
    print("删除成功")
# 如果不是 "1",函数自然结束(隐式 return)

不需要 else:

  • 选择 "0" 或其他时,函数直接结束。
  • 自动返回到调用处。
  • 等同于在末尾有一个隐式的 return。

总结

代码结构

# 1. 全局变量
card_list = []

# 2. 功能函数定义
def show_menu():
    """显示菜单"""
    ...

def add_card():
    """新建名片"""
    ...

def show_all():
    """显示全部"""
    ...

def search_card():
    """查询名片"""
    ...

def delete_card(find_dict):
    """删除名片"""
    ...

# 3. 主函数
def run():
    """主控制函数"""
    while True:
        # 协调各功能函数
        ...

# 4. 程序入口
run()

函数调用关系图

run()(主函数)
├─ show_menu() 显示菜单
├─ add_card() 新建名片
├─ show_all() 显示全部
└─ search_card() 查询名片
└─ delete_card() 删除名片(被查询函数调用)

数据流动图

用户输入

变量(name, phone, wechat, email)

字典(card_dict)

列表(card_list)

遍历/查询/删除

格式化输出

用户查看

核心技术点

技术点 知识点 应用场景
数据结构 列表+字典嵌套 管理多条结构化数据
循环控制 while True + break 程序持续运行+退出机制
条件判断 if/elif/else 根据用户选择执行不同功能
函数调用 函数嵌套调用 功能模块化组织
参数传递 形参与实参 函数间数据传递
遍历操作 for...in / for...else 遍历容器+查询判断
列表操作 append() / remove() 添加和删除元素
字典操作 键值对存取 结构化数据存储
空值判断 len() / if 判断 避免空数据错误
格式化输出 f-string / \t 美化显示效果

设计模式

  1. MVC 思想体现

    • Model(数据):card_list 全局列表。
    • View(视图):show_menu(), show_all() 显示函数。
    • Controller(控制):run() 主函数。
  2. 单一职责原则
    每个函数只做一件事:

    • show_menu() 只负责显示。
    • add_card() 只负责添加。
    • search_card() 只负责查询。
  3. 代码复用
    通过函数封装,避免重复代码:

    • 显示菜单:只需调用 show_menu()。
    • 格式化输出:统一的打印格式。

常见问题与解决

为什么需要全局变量

问题:为什么 card_list 要定义在函数外?
答案:

  • 全局变量可以被所有函数访问。
  • 作为数据共享的容器。
  • 多个函数需要操作同一个列表。

为什么用字典

问题:为什么不直接用列表存储名片?
答案:

# 使用列表(不推荐)
card = ["张伟", "13912345678", "zhangwei123", "zhangwei@example.com"]
# 问题:不知道每个位置代表什么,容易混乱

# 使用字典(推荐)
card = {
    "name_key": "张伟",
    "phone_key": "13912345678",
    "wechat_key": "zhangwei123",  
    "email_key": "zhangwei@example.com"
}
# 优势:键名清晰表达含义,易于理解和维护

为什么用 while True

问题:死循环不是bug吗?
答案:

  • 系统需要持续运行,等待用户操作。
  • 配合 break 提供退出机制。
  • 这是交互式程序的标准模式。

数据为什么会丢失

问题:为什么关闭程序后数据不见了?
答案:

  • 当前数据只存在内存中(临时存储)。
  • 程序关闭,内存释放,数据丢失。
  • 解决方案:下节课学习文件操作,将数据保存到文件。

扩展思考

可以改进的地方

  1. 输入验证

    • 电话号码格式检查。
    • email 格式验证。
    • 必填项检查。
  2. 功能增强

    • 修改名片信息。
    • 批量删除。
    • 模糊查询。
    • 排序功能。
  3. 数据持久化

    • 保存到文件。
    • 读取已保存的数据。
    • 自动备份。
  4. 界面优化

    • 清屏功能。
    • 彩色输出。
    • 进度提示。

相关技术延伸

数据库应用
当前:列表+字典(内存)
↓ 升级
将来:MySQL(持久化)

Web 应用
当前:控制台程序
↓ 升级
将来:Flask/Django Web界面

移动应用
当前:本地运行
↓ 升级
将来:Kivy移动端开发

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐