数据分析笔记13:Python 名片管理系统-练习案例
数据分析笔记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} 的名片")
执行流程:
- 收集信息 → 使用 input() 获取用户输入。
- 构建字典 → 使用键值对组织数据。
- 追加到列表 → 使用 append() 添加到容器。
- 反馈确认 → 打印成功信息。
关键技术点
字典的创建:
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(终止)
↓ 否
打印表头
↓
遍历列表
↓
逐个打印名片信息
↓
结束
关键技术点
- 空值判断:
if len(card_list) == 0:
print("没有任何名片记录")
return # 立即终止函数
为什么判断?
- 避免空列表遍历时出错。
- 提供友好的用户提示。
- 提前终止,节省资源。
- return 的妙用:
return # 不返回任何值,仅终止函数
作用:
- 遇到 return 立即退出函数。
- 后面的代码不再执行。
- 回到调用函数的地方。
- 格式化输出
使用 \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']}")
- 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 退出循环
↓ 否
继续下一个字典
↓
遍历结束仍未找到?
↓
打印“没有找到”
关键技术点
- for...else 语法:
for d in card_list:
if 条件:
# 找到了
break
else:
# 遍历完都没找到才执行
print("没有找到")
理解要点:
- else 属于 for 循环,不属于 if。
- 只有正常遍历完(没有 break)才执行 else。
- 如果 break 退出,则不执行 else。
- 函数嵌套调用:
delete_card(d) # 在查询函数中调用删除函数
调用流程:
search_card() 执行中
↓ 找到名片
暂停 search_card()
↓
跳转到 delete_card()
↓ 执行完毕
返回 search_card()
↓
break 退出循环
↓
search_card() 结束
- 参数传递:
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 或其他,函数自然结束,返回上级
关键技术点
- 形参与实参:
实参(实际参数):
search_card() 中:
delete_card(d) # d 是实参,传递实际数据
形参(形式参数):
def delete_card(find_dict): # find_dict 是形参,接收数据
理解要点:
- 形参和实参的名称可以不同。
- 形参只是一个“占位符”,接收传入的数据。
- 实参是真实存在的数据。
- 数量必须匹配,名称不要求一致。
- remove() 方法:
card_list.remove(find_dict) # 从列表中移除指定元素
工作原理:
- 在列表中查找该字典。
- 找到后将其移除。
- 列表长度减1。
示例:
删除前
card_list = [{"name": "张伟"}, {"name": "李娜"}]
执行删除
card_list.remove({"name": "张伟"})
删除后
card_list = [{"name": "李娜"}]
- 函数的自然结束:
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 | 美化显示效果 |
设计模式
-
MVC 思想体现
- Model(数据):card_list 全局列表。
- View(视图):show_menu(), show_all() 显示函数。
- Controller(控制):run() 主函数。
-
单一职责原则
每个函数只做一件事:- show_menu() 只负责显示。
- add_card() 只负责添加。
- search_card() 只负责查询。
-
代码复用
通过函数封装,避免重复代码:- 显示菜单:只需调用 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 提供退出机制。
- 这是交互式程序的标准模式。
数据为什么会丢失
问题:为什么关闭程序后数据不见了?
答案:
- 当前数据只存在内存中(临时存储)。
- 程序关闭,内存释放,数据丢失。
- 解决方案:下节课学习文件操作,将数据保存到文件。
扩展思考
可以改进的地方
-
输入验证
- 电话号码格式检查。
- email 格式验证。
- 必填项检查。
-
功能增强
- 修改名片信息。
- 批量删除。
- 模糊查询。
- 排序功能。
-
数据持久化
- 保存到文件。
- 读取已保存的数据。
- 自动备份。
-
界面优化
- 清屏功能。
- 彩色输出。
- 进度提示。
相关技术延伸
数据库应用
当前:列表+字典(内存)
↓ 升级
将来:MySQL(持久化)
Web 应用
当前:控制台程序
↓ 升级
将来:Flask/Django Web界面
移动应用
当前:本地运行
↓ 升级
将来:Kivy移动端开发
更多推荐



所有评论(0)