当前位置:首页>python>【Python】Day13:第二周复习与实战(上)

【Python】Day13:第二周复习与实战(上)

  • 2026-10-11 07:32:54
【Python】Day13:第二周复习与实战(上)

🎯 学习目标

  1. 复习巩固第二周所学:列表、字典、字符串方法、元组、集合
  2. 学会项目需求分析:把一个大问题拆解成小问题
  3. 学会数据结构设计:选择合适的数据类型存储通讯录数据
  4. 完成通讯录的基础框架搭建:主菜单循环 + 基本的添加和查看功能
  5. 理解程序 = 数据结构 + 算法的思想

一、第二周知识回顾

  1. 列表核心要点
    # 创建lst = [1, 2, 3]# 增lst.append(4)           # 末尾加一个lst.insert(0, 0)        # 指定位置插入lst.extend([5, 6])      # 末尾加多个# 删lst.remove(3)           # 按值删lst.pop()               # 删末尾并返回lst.pop(0)              # 按索引删del lst[1]              # 按索引删# 改lst[0] = 99# 索引赋值# 查lst.index(4)            # 找索引lst.count(2)            # 计次数2 in lst                # 是否存在# 排序lst.sort()              # 原地排sorted(lst)             # 返回新的lst.reverse()           # 原地反转
  2. 字典核心要点
    # 创建d = {"name": "小王", "age": 18}# 增/改d["city"] = "北京"# 键存在就改,不存在就增d.update({"age": 19})   # 批量更新# 删del d["city"]           # 删除键值对d.pop("age", 0)         # 删除并返回值# 查d["name"]               # 键不存在会报错d.get("name", "未知")   # 安全访问# 遍历for k, v in d.items():    print(k, v)
  3. 字符串方法核心要点
    s = "  Hello, World!  "s.strip()               # "Hello, World!"s.split(",")            # ["  Hello", " World!  "]",".join(["a", "b"])    # "a,b"s.replace("World", "Python")s.find("World")         # 索引s.count("l")            # 次数s.lower() / s.upper()   # 大小写
  4. 元组与集合核心要点
    # 元组:不可变t = (1, 2, 3)a, b, c = t             # 解包# 集合:去重、交集s = {1, 2, 3}s.add(4){1, 2} & {2, 3}         # {2}  交集{1, 2} | {2, 3}         # {1, 2, 3}  并集

二、项目需求分析:命令行通讯录

  1. 功能需求一个命令行通讯录程序,支持以下操作:

    功能
    说明
    添加联系人
    输入姓名、电话、城市等信息
    查看所有联系人
    列表显示所有联系人的简要信息
    查找联系人
    按姓名查找,显示详细信息
    修改联系人
    修改已有联系人的信息
    删除联系人
    删除指定联系人
    退出程序
    保存并退出
  2. 交互方式

    ========== 命令行通讯录 ==========1. 添加联系人2. 查看所有联系人3. 查找联系人4. 修改联系人5. 删除联系人0. 退出=================================请选择操作(0-5):
  3. 需求拆解:从大到小

    通讯录程序├── 数据结构设计(用什么存?)├── 主菜单循环(怎么交互?)├── 功能模块│   ├── 添加联系人│   ├── 查看所有联系人│   ├── 查找联系人│   ├── 修改联系人│   └── 删除联系人└── 退出处理

三、数据结构设计

  1. 方案对比

    方案
    结构
    优点
    缺点
    方案A
    列表存姓名、列表存电话
    简单
    需要两个列表同步管理,容易出错
    方案B
    列表存字典
    灵活,可扩展
    按姓名查找需要遍历
    方案C
    字典嵌套字典
    按姓名直接查找
    同名怎么办?
  2. 最终方案:字典嵌套字典,以姓名为键

    contacts = {"小王": {"phone": "138-0001-0001","city": "北京","email": "xiaowang@qq.com"    },"小李": {"phone": "139-0002-0002","city": "上海","email": "xiaoli@163.com"    }}
    • 按姓名查找最快:contacts["小王"]一步到位
    • 每个人的信息结构清晰:子字典
    • 容易增删改查:字典的强项
    • 为什么选这个方案?
    • 潜在问题:同名怎么办?本次项目简化处理,同名视为同一人(覆盖)
  3. 预设数据

    # 预设几个联系人,方便测试contacts = {"小王": {"phone": "138-0001-0001", "city": "北京", "email": "xiaowang@qq.com"},"小李": {"phone": "139-0002-0002", "city": "上海", "email": "xiaoli@163.com"},"小张": {"phone": "137-0003-0003", "city": "广州", "email": "xiaozhang@gmail.com"}}

四、搭建基础框架:主菜单循环

  1. 核心结构:while True +input +if/elif/else
    # 通讯录数据contacts = {"小王": {"phone": "138-0001-0001", "city": "北京", "email": "xiaowang@qq.com"},"小李": {"phone": "139-0002-0002", "city": "上海", "email": "xiaoli@163.com"},"小张": {"phone": "137-0003-0003", "city": "广州", "email": "xiaozhang@gmail.com"}}# 主循环whileTrue:    print("\n========== 命令行通讯录 ==========")    print("1. 添加联系人")    print("2. 查看所有联系人")    print("3. 查找联系人")    print("4. 修改联系人")    print("5. 删除联系人")    print("0. 退出")    print("==================================")    choice = input("请选择操作(0-5):").strip()if choice == "0":        print("感谢使用,再见!")breakelif choice == "1":        print("【添加联系人】")# TODO: 今天实现elif choice == "2":        print("【查看所有联系人】")# TODO: 今天实现elif choice == "3":        print("【查找联系人】(明天实现)")elif choice == "4":        print("【修改联系人】(明天实现)")elif choice == "5":        print("【删除联系人】(明天实现)")else:        print("⚠️ 无效输入,请输入 0-5 之间的数字")
  2. 理解框架结构
    • while True:无限循环,直到break才退出
    • input()获取用户选择
    • if/elif/else根据选择执行不同功能
    • .strip()清理输入的首尾空白
    • 每个# TODO是今天和明天要填充的功能
  3. 为什么用while True而不是直接顺序执行?
    • 顺序执行:跑一次就结束了,用户只能做一次操作
    • while True:程序持续运行,用户可以反复操作,直到选择退出
    • 这是交互式命令行程序的标准模式

五、实现添加联系人

  1. 添加逻辑
    输入姓名 → 姓名为空则提示 → 姓名已存在则确认是否覆盖 →输入电话 → 电话为空则提示 → 输入城市 → 输入邮箱 →写入字典 → 提示成功
  2. 代码实现
    # === 添加联系人(嵌在 choice == "1" 分支中)===name = input("  请输入姓名:").strip()ifnot name:    print("⚠️ 姓名不能为空!")else:if name in contacts:        print(f"⚠️ 联系人 '{name}' 已存在!")        overwrite = input("  是否覆盖?(y/n):").strip().lower()if overwrite != "y":            print("  取消添加。")else:            phone = input("  请输入电话:").strip()            city = input("  请输入城市:").strip()            email = input("  请输入邮箱:").strip()            contacts[name] = {"phone": phone, "city": city, "email": email}            print(f"✅ 联系人 '{name}' 覆盖成功!")else:        phone = input("  请输入电话:").strip()        city = input("  请输入城市:").strip()        email = input("  请输入邮箱:").strip()        contacts[name] = {"phone": phone, "city": city, "email": email}        print(f"✅ 联系人 '{name}' 添加成功!")
  3. 观察:上面有重复代码,能不能精简?
    # === 添加联系人(精简版)===name = input("  请输入姓名:").strip()can_add = True# 标志:是否可以继续添加ifnot name:    print("⚠️ 姓名不能为空!")    can_add = Falseif can_add and name in contacts:    print(f"⚠️ 联系人 '{name}' 已存在!")    overwrite = input("  是否覆盖?:").strip().lower()if overwrite != "y":        print("  取消添加。")        can_add = Falseif can_add:    phone = input("  请输入电话:").strip()ifnot phone:        print("⚠️ 电话不能为空!")else:        city = input("  请输入城市:").strip()        email = input("  请输入邮箱:").strip()if email and"@"notin email:            print("⚠️ 邮箱格式不正确,将不保存邮箱")            email = ""        contacts[name] = {"phone": phone, "city": city, "email": email}        print(f"✅ 联系人 '{name}' 添加成功!")
    • "已存在且确认覆盖"和"不存在"的后续操作是一样的:输入电话、城市、邮箱、写入字典
    • 我们可以用一个标志变量can_add来控制是否继续:

六、实现查看所有联系人

  1. 查看逻辑
    判断通讯录是否为空 →为空则提示 →不为空则打印表头 → 遍历字典打印每行 → 打印统计信息
  2. 代码实现
    # === 查看所有联系人(嵌在 choice == "2" 分支中)===ifnot contacts:    print("📭 通讯录为空!")else:# 表头    print(f"  {'序号':<4}{'姓名':<8}{'电话':<18}{'城市':<8}{'邮箱':<20}")    print("  " + "-" * 58)# 表格内容:用 enumerate 给每行加序号for i, (name, info) in enumerate(contacts.items(), 1):        phone = info["phone"]        city = info.get("city", "未知") or"未知"        email = info.get("email", "无") or"无"        print(f"  {i:<4}{name:<8}{phone:<18}{city:<8}{email:<20}")    print("  " + "-" * 58)    print(f"  共 {len(contacts)} 位联系人")# 城市统计    city_count = {}for info in contacts.values():        city = info.get("city", "未知") or"未知"        city_count[city] = city_count.get(city, 0) + 1    city_info = "、".join(f"{c}{n}人"for c, n in city_count.items())    print(f"  城市分布:{city_info}")
  3. 格式化输出说明
    • {name:<8} 表示左对齐,占8个字符宽度
    • enumerate(contacts.items(), 1)从1开始编号 -info.get("city", "未知") or "未知" 双重保护:键不存在时返回"未知",值为空字符串时也返回"未知"

七、整合:今天完成的完整代码

# ==========================================#        命令行通讯录(Day13 版本)# ==========================================# 通讯录数据contacts = {"小王": {"phone": "138-0001-0001", "city": "北京", "email": "xiaowang@qq.com"},"小李": {"phone": "139-0002-0002", "city": "上海", "email": "xiaoli@163.com"},"小张": {"phone": "137-0003-0003", "city": "广州", "email": "xiaozhang@gmail.com"}}# 主循环whileTrue:    print("\n========== 命令行通讯录 ==========")    print("1. 添加联系人")    print("2. 查看所有联系人")    print("3. 查找联系人")    print("4. 修改联系人")    print("5. 删除联系人")    print("0. 退出")    print("==================================")    choice = input("请选择操作(0-5):").strip()if choice == "0":        print("感谢使用,再见!")breakelif choice == "1":# ---- 添加联系人 ----        name = input("  请输入姓名:").strip()        can_add = Trueifnot name:            print("⚠️ 姓名不能为空!")            can_add = Falseif can_add and name in contacts:            print(f"⚠️ 联系人 '{name}' 已存在!")            overwrite = input("  是否覆盖?:").strip().lower()if overwrite != "y":                print("  取消添加。")                can_add = Falseif can_add:            phone = input("  请输入电话:").strip()ifnot phone:                print("⚠️ 电话不能为空!")else:                city = input("  请输入城市:").strip()                email = input("  请输入邮箱:").strip()if email and"@"notin email:                    print("⚠️ 邮箱格式不正确,将不保存邮箱")                    email = ""                contacts[name] = {"phone": phone, "city": city, "email": email}                print(f"✅ 联系人 '{name}' 添加成功!")elif choice == "2":# ---- 查看所有联系人 ----ifnot contacts:            print("📭 通讯录为空!")else:            print(f"  {'序号':<4}{'姓名':<8}{'电话':<18}{'城市':<8}{'邮箱':<20}")            print("  " + "-" * 58)for i, (name, info) in enumerate(contacts.items(), 1):                phone = info["phone"]                city = info.get("city", "未知") or"未知"                email = info.get("email", "无") or"无"                print(f"  {i:<4}{name:<8}{phone:<18}{city:<8}{email:<20}")            print("  " + "-" * 58)            print(f"  共 {len(contacts)} 位联系人")            city_count = {}for info in contacts.values():                city = info.get("city", "未知") or"未知"                city_count[city] = city_count.get(city, 0) + 1            city_info = "、".join(f"{c}{n}人"for c, n in city_count.items())            print(f"  城市分布:{city_info}")elif choice == "3":        print("【查找联系人】(明天实现)")elif choice == "4":        print("【修改联系人】(明天实现)")elif choice == "5":        print("【删除联系人】(明天实现)")else:        print("⚠️ 无效输入,请输入 0-5 之间的数字")

⚠️ 常见坑

  1. 忘记strip()导致空格干扰
    name = input("请输入姓名:")       # 用户可能输入 "  小王  "name = input("请输入姓名:").strip() # ✅ 清理空白
  2. if not contacts判断字典是否为空
    # ✅ 正确:空字典的布尔值是 Falseifnot contacts:    print("通讯录为空")# 也可以,但不简洁# if len(contacts) == 0:
  3. input()返回的永远是字符串
    choice = input("请选择:")    # 用户输入 1,choice 是 "1" 不是 1# 所以用 choice == "1" 而不是 choice == 1
  4. 格式化输出时中英文混排对齐困难
    # 中文字符占2个显示宽度,但Python计算长度时算1个# 简单项目中用足够宽度"差不多对齐"即可# 完美对齐需要额外处理,目前不纠结

✍️ 实战练习

  1. 运行完整代码并测试
    • 选择 2,查看预设的3个联系人
    • 选择 1,添加"赵六",电话"136-0004-0004",城市"深圳",邮箱"zhaoliu@qq.com"
    • 选择 2,确认赵六已添加,且城市统计正确
    • 选择 1,输入"小王"(已存在),选择不覆盖,确认取消
    • 选择 1,姓名直接回车,确认提示"不能为空"
    • 要求:把上面的代码复制到编辑器中运行,依次测试添加和查看功能。
    • 测试用例:
  2. 加强输入验证
    • 电话不能为空(已在代码中实现)
    • 邮箱如果填写了,必须包含@(已在代码中实现)
    • 新增:城市如果为空,自动设为"未知"
    • 要求:在添加联系人时,增加以下验证:
    • 提示:
      city = input("  请输入城市:").strip()ifnot city:    city = "未知"
  3. 美化输出
    • 要求:修改查看联系人的输出,增加分隔符、对齐调整等,让表格更美观。
    • 提示:尝试修改print("  " + "-" * 58)中的分隔符为=或+,看看效果。
  4. 思考题
    • 如果要支持一个联系人有多个电话号码,数据结构该怎么改?
    • 如果要支持按城市筛选联系人,代码该怎么写?
    • (这些思考会在 Day14 的拓展中涉及)

✅ 自测清单

  • [ ] 能回顾列表、字典、字符串方法、元组、集合的核心用法
  • [ ] 能对项目做需求分析,拆解成小模块
  • [ ] 能选择合适的数据结构(字典嵌套字典)存储通讯录数据
  • [ ] 能搭建主菜单循环框架(while True+input+if/elif)
  • [ ] 能实现添加联系人功能,处理重名和空值情况
  • [ ] 能实现查看所有联系人功能,用格式化输出表格
  • [ ] 理解用标志变量can_add控制流程,避免深层嵌套
  • [ ] 理解input()返回字符串,所以用choice == "1"而非choice == 1

最新文章

随机文章