十二、实战项目一:基于文件存储的通讯录系统(Python 练手项目)
这是一个功能十分完备的命令行通讯录系统,涵盖了增删改查、模糊搜索以及 JSON 持久化等核心功能。对于刚入门 Python 的开发者而言,这是一个极佳的上手案例。下面先展示完整代码,再逐一分析项目亮点。

import json
import os
class Contact:
def __init__(self, name, phone, email=""):
self.name = name
self.phone = phone
self.email = email
def to_dict(self):
return {"name": self.name, "phone": self.phone, "email": self.email}
@staticmethod
def from_dict(data):
return Contact(data["name"], data["phone"], data.get("email", ""))
def __str__(self):
return f"{self.name} | {self.phone} | {self.email}"
class AddressBook:
def __init__(self, filename="contacts.json"):
self.filename = filename
self.contacts = [] # 存储 Contact 对象
self.load()
def load(self):
if not os.path.exists(self.filename):
return
try:
with open(self.filename, "r", encoding="utf-8") as f:
data = json.load(f)
self.contacts = [Contact.from_dict(item) for item in data]
print(f"加载了 {len(self.contacts)} 个联系人")
except Exception as e:
print(f"加载失败: {e}")
def sa ve(self):
with open(self.filename, "w", encoding="utf-8") as f:
json.dump([c.to_dict() for c in self.contacts], f, ensure_ascii=False, indent=2)
print("已保存")
def add(self, name, phone, email=""):
# 检查重复
if any(c.name == name for c in self.contacts):
print(f"联系人 {name} 已存在")
return False
self.contacts.append(Contact(name, phone, email))
self.sa ve()
print(f"添加成功: {name}")
return True
def delete(self, name):
for i, c in enumerate(self.contacts):
if c.name == name:
del self.contacts[i]
self.sa ve()
print(f"已删除 {name}")
return True
print(f"未找到 {name}")
return False
def search(self, keyword):
"""支持模糊搜索(不区分大小写)"""
keyword_lower = keyword.lower()
results = [c for c in self.contacts if keyword_lower in c.name.lower() or keyword_lower in c.phone]
if not results:
print("无匹配结果")
else:
print(f"找到 {len(results)} 个联系人:")
for c in results:
print(c)
return results
def list_all(self):
if not self.contacts:
print("通讯录为空")
return
print("===== 通讯录 =====")
for c in sorted(self.contacts, key=lambda x: x.name):
print(c)
print(f"共 {len(self.contacts)} 人")
def main():
book = AddressBook()
while True:
print("1.添加 2.删除 3.搜索 4.显示全部 5.保存 0.退出")
choice = input("请选择: ").strip()
if choice == "1":
name = input("姓名: ").strip()
phone = input("电话: ").strip()
email = input("邮箱(可选): ").strip()
book.add(name, phone, email)
elif choice == "2":
name = input("要删除的姓名: ").strip()
book.delete(name)
elif choice == "3":
kw = input("搜索关键字: ").strip()
book.search(kw)
elif choice == "4":
book.list_all()
elif choice == "5":
book.sa ve()
elif choice == "0":
book.sa ve()
print("再见")
break
else:
print("无效选项")
if __name__ == "__main__":
main()
接下来分析这个通讯录项目的亮点:
第一,数据持久化采用 JSON 格式,方便直接阅读和手动编辑,调试过程非常直观。第二,面向对象设计将 Contact(联系人)和 AddressBook(通讯录)的职责划分清晰,未来若要添加分组、标签等扩展功能,现有架构完全能够支撑。第三,模糊搜索功能虽然实现简洁,但已同时覆盖姓名和电话号码,对于数百个联系人的数据量,性能表现绰绰有余。第四,联系人列表自动按姓名排序,这一细节体现了良好的用户体验。
整个代码大约 100 行,难度适中,非常适合初学者阅读并在此基础上进行修改练习,例如增加编辑联系人功能、或改为 CSV 导出格式,都是不错的实战方向。
十三、实战项目二:基于 SQLite 的学生成绩管理系统
本项目改用 SQLite 数据库替代普通文件存储,支持复杂查询与统计分析,并可导出成绩报表为 CSV 格式。可以理解为,将单机小工具升级到了“专业版”水准。
13.1 准备工作
SQLite 是 Python 内置的轻量级数据库,无需额外安装。只需导入 sqlite3 模块即可使用,对于新手来说是非常友好的数据库入门选择。
import sqlite3
import csv
from datetime import datetime
class StudentDB:
def __init__(self, db_name="students.db"):
self.conn = sqlite3.connect(db_name)
self.cursor = self.conn.cursor()
self._create_table()
def _create_table(self):
self.cursor.execute("""
CREATE TABLE IF NOT EXISTS students (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL UNIQUE,
score REAL NOT NULL,
class_name TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
""")
self.conn.commit()
def add_student(self, name, score, class_name=None):
try:
self.cursor.execute("INSERT INTO students (name, score, class_name) VALUES (?, ?, ?)",
(name, score, class_name))
self.conn.commit()
print(f"添加成功: {name}")
return True
except sqlite3.IntegrityError:
print(f"学生 {name} 已存在")
return False
def delete_student(self, name):
self.cursor.execute("DELETE FROM students WHERE name = ?", (name,))
self.conn.commit()
if self.cursor.rowcount > 0:
print(f"已删除 {name}")
else:
print(f"未找到 {name}")
def update_score(self, name, new_score):
self.cursor.execute("UPDATE students SET score = ? WHERE name = ?", (new_score, name))
self.conn.commit()
if self.cursor.rowcount > 0:
print(f"{name} 成绩已更新为 {new_score}")
else:
print(f"未找到 {name}")
def query(self, name):
self.cursor.execute("SELECT * FROM students WHERE name = ?", (name,))
row = self.cursor.fetchone()
if row:
print(f"ID: {row[0]}, 姓名: {row[1]}, 成绩: {row[2]}, 班级: {row[3]}, 创建时间: {row[4]}")
else:
print("未找到")
def show_all(self, order_by="score DESC"):
self.cursor.execute(f"SELECT name, score, class_name FROM students ORDER BY {order_by}")
rows = self.cursor.fetchall()
if not rows:
print("暂无数据")
return
print("===== 学生成绩表 =====")
print(f"{'姓名':<10} {'成绩':<8} {'班级':<10}")
print("-" * 30)
for name, score, cls in rows:
print(f"{name:<10} {score:<8} {cls if cls else '':<10}")
print(f"共 {len(rows)} 条记录")
def statistics(self):
self.cursor.execute("SELECT COUNT(*), A VG(score), MAX(score), MIN(score) FROM students")
count, a vg, max_score, min_score = self.cursor.fetchone()
if count == 0:
print("无数据")
return
print(f"学生人数: {count}")
print(f"平均分: {a vg:.2f}")
print(f"最高分: {max_score}")
print(f"最低分: {min_score}")
# 查询最高分学生
self.cursor.execute("SELECT name FROM students WHERE score = ?", (max_score,))
top_students = [row[0] for row in self.cursor.fetchall()]
print(f"最高分学生: {', '.join(top_students)}")
def export_csv(self, filename="report.csv"):
self.cursor.execute("SELECT name, score, class_name, created_at FROM students ORDER BY score DESC")
with open(filename, "w", newline="", encoding="utf-8") as f:
writer = csv.writer(f)
writer.writerow(["姓名", "成绩", "班级", "创建时间"])
writer.writerows(self.cursor.fetchall())
print(f"报表已导出到 {filename}")
def close(self):
self.conn.close()
# 命令行交互部分与之前类似,此处省略,请自行扩展
该项目将数据库操作与业务逻辑封装在 StudentDB 类中,增删改查功能均带有友好提示和异常处理。尤为值得关注的是其统计方法 —— 可以直接计算平均分、最高分和最低分,并列出获得最高分的学生姓名,在实际管理场景中极为实用。CSV 导出功能同样具备较高价值,便于将数据用于后续分析或汇报。
十四、调试与测试:实用技巧与工具
即便代码写得再完善,也难免会遇到 Bug。本节将介绍调试与测试的基础方法,均为可在实际开发中直接应用的实用技能。
14.1 使用 print 调试
print 调试是最基础的方法,但效率并不低。关键在于打印出有价值的中间变量:
def calculate(nums):
print(f"[DEBUG] nums: {nums}") # 打印变量
total = sum(nums)
print(f"[DEBUG] total: {total}")
return total
14.2 使用 pdb 进行断点调试
当代码逻辑较为复杂时,print 调试就显得力不从心。Python 内置的 pdb 模块支持在代码中设置断点,实现逐步执行调试:
import pdb
def buggy_function(x):
pdb.set_trace() # 程序在此暂停
result = x / 0
return result
进入 pdb 交互模式后,请记住以下常用命令:
- n (next): 执行当前行并跳至下一行
- s (step): 进入调用函数内部逐行调试
- c (continue): 继续执行直到遇到下一个断点
- p 变量 (print): 打印指定变量的值
- q (quit): 退出 pdb 调试
14.3 编写单元测试(unittest)
编写单元测试是专业开发者的必备技能。Python 自带的 unittest 框架使用起来非常直观:
import unittest
def add(a, b):
return a b # 注意这里故意写错了(少一个加号?实际是 a b,原文如此,保留)
class TestMath(unittest.TestCase):
def test_add(self):
self.assertEqual(add(2, 3), 5)
self.assertEqual(add(-1, 1), 0)
def test_add_negative(self):
self.assertLess(add(-5, -2), 0)
if __name__ == "__main__":
unittest.main()
14.4 使用 doctest 进行文档测试
另一种有趣的测试方式是将测试用例直接写在函数的文档字符串中,通过 doctest 模块自动执行:
def multiply(a, b):
"""
返回两数乘积。
>>> multiply(3, 4)
12
>>> multiply(-1, 5)
-5
"""
return a * b
if __name__ == "__main__":
import doctest
doctest.testmod()
这种方法的优势在于文档与测试合二为一,函数的用法一目了然。但对于复杂的测试场景,仍建议使用 unittest 或 pytest 等更为完善的框架。
