🐍 综合练习 — Day13-Day19 大串联
🕐 预计用时:3-4 小时 | 🎯 目标:用函数、推导式、文件操作、异常处理完成两个完整项目
📖 今日目录
1. 项目 1:词频统计程序 📊
读取文本文件,统计词频,生成排行榜,支持多种输出格式。
📋 需求分析
🎯 完整代码
import stringimport osfrom collections import Counter# ============ 配置 ============STOP_WORDS = { "the", "a", "an", "is", "are", "was", "were", "be", "been", "have", "has", "had", "do", "does", "did", "will", "would", "shall", "should", "may", "might", "can", "could", "to", "of", "in", "for", "on", "with", "at", "by", "from", "as", "into", "and", "or", "but", "if", "then", "so", "not", "no", "it", "its", "this", "that", "these", "those", "i", "you", "he", "she", "we", "they", "me", "him", "her", "us", "them",}# ============ 核心函数 ============def load_text(filename): """加载文本文件""" try: with open(filename, "r", encoding="utf-8") as f: return f.read() except FileNotFoundError: print(f"❌ 文件不存在: {filename}") return None except UnicodeDecodeError: with open(filename, "r", encoding="gbk") as f: return f.read()def clean_text(text): """清洗文本:转小写、去标点""" text = text.lower() for char in string.punctuation: text = text.replace(char, " ") return textdef extract_words(text): """提取单词列表""" return [w for w in text.split() if len(w) > 1]def count_words(words, remove_stopwords=True): """统计词频""" if remove_stopwords: words = [w for w in words if w not in STOP_WORDS] return Counter(words)def get_top_n(freq, n=20): """获取前 N 个高频词""" return freq.most_common(n)# ============ 输出函数 ============def print_table(top_words, title="词频统计"): """表格形式输出""" if not top_words: print(" 暂无数据") return max_count = top_words[0][1] print(f"\n📊 {title}(前 {len(top_words)} 名)") print("-" * 45) for rank, (word, count) in enumerate(top_words, 1): bar = "█" * int(count / max_count * 20) print(f" {rank:2d}. {word:15s} | {bar} {count}") print("-" * 45)def print_word_cloud(top_words): """词云形式输出(按大小排列)""" if not top_words: return max_count = top_words[0][1] print("\n☁️ 词云:") sizes = [] for word, count in top_words: ratio = count / max_count if ratio > 0.8: sizes.append(f"**{word}**") elif ratio > 0.5: sizes.append(f"*{word}*") else: sizes.append(word) print(" " + " ".join(sizes))def save_report(freq, filename="word_report.txt", top_n=50): """保存完整报告到文件""" with open(filename, "w", encoding="utf-8") as f: f.write("=" * 50 + "\n") f.write("词频统计报告\n") f.write("=" * 50 + "\n\n") f.write(f"总词数: {sum(freq.values())}\n") f.write(f"不重复词数: {len(freq)}\n\n") f.write(f"Top {top_n}:\n") f.write("-" * 30 + "\n") for rank, (word, count) in enumerate(freq.most_common(top_n), 1): f.write(f" {rank:3d}. {word:15s} {count:5d}\n") print(f"✅ 报告已保存: {filename}")# ============ 分析函数 ============def analyze_text(filename, top_n=20): """完整分析流程""" print("=" * 50) print("📊 词频分析器") print("=" * 50) # 1. 加载 text = load_text(filename) if text is None: return print(f"📄 文件大小: {len(text)} 字符") # 2. 清洗 cleaned = clean_text(text) # 3. 提取 words = extract_words(cleaned) print(f"📝 总单词数: {len(words)}") # 4. 统计(含停用词) all_freq = count_words(words, remove_stopwords=False) print(f"📚 不重复词数: {len(all_freq)}") # 5. 统计(去停用词) freq = count_words(words, remove_stopwords=True) print(f"🔍 有效词数: {len(freq)}") # 6. 输出 top = get_top_n(freq, top_n) print_table(top) print_word_cloud(top[:10]) # 7. 保存 save_report(freq, "word_report.txt") # 8. 额外统计 lengths = {len(w) for w in freq.keys()} print(f"\n📏 单词长度范围: {min(lengths)}-{max(lengths)} 字母") avg_len = sum(len(w) * c for w, c in freq.items()) / sum(freq.values()) print(f"📏 平均单词长度: {avg_len:.1f} 字母")# ============ 生成测试文件 ============def create_sample(): """创建示例文本""" sample = """Python is a high-level, general-purpose programming language.Its design philosophy emphasizes code readability with the use of significant indentation.Python is dynamically typed and garbage-collected.It supports multiple programming paradigms, including structured, object-oriented, and functional programming.Python was conceived in the late 1980s by Guido van Rossum at Centrum Wiskunde & Informatica in the Netherlands.Python consistently ranks as one of the most popular programming languages.Python is used extensively in scientific computing, data analysis, artificial intelligence, and web development.The language provides constructs intended to enable clear programs on both small and large scales.Python interpreters are available for many operating systems, allowing Python code to run on a wide variety of systems.""" with open("sample.txt", "w", encoding="utf-8") as f: f.write(sample) print("✅ 示例文件已创建: sample.txt") return "sample.txt"# ============ 主程序 ============if __name__ == "__main__": filename = create_sample() analyze_text(filename, top_n=15)
2. 项目 2:联系人通讯录 📇
一个支持增删改查、搜索、导入导出的命令行通讯录,数据持久化到 JSON 文件。
📋 需求分析
🎯 完整代码
import jsonimport osimport csvfrom datetime import datetime# ============ 数据结构 ============# contacts = {# "id_001": {# "name": "张三",# "phone": "13800138001",# "email": "zhangsan@test.com",# "group": "朋友",# "created": "2024-01-15 10:30:00"# },# ...# }DATA_FILE = "contacts.json"ID_COUNTER = 0# ============ 文件操作 ============def load_contacts(): """从 JSON 文件加载通讯录""" global ID_COUNTER if not os.path.exists(DATA_FILE): return {} try: with open(DATA_FILE, "r", encoding="utf-8") as f: data = json.load(f) if data: max_id = max(int(k.split("_")[1]) for k in data.keys()) ID_COUNTER = max_id return data except (json.JSONDecodeError, KeyError) as e: print(f"⚠️ 数据文件损坏: {e}") return {}def save_contacts(contacts): """保存通讯录到 JSON 文件""" with open(DATA_FILE, "w", encoding="utf-8") as f: json.dump(contacts, f, indent=2, ensure_ascii=False)def generate_id(): """生成唯一 ID""" global ID_COUNTER ID_COUNTER += 1 return f"id_{ID_COUNTER:04d}"# ============ 核心操作 ============def add_contact(contacts): """添加联系人""" print("\n➕ 添加联系人") name = input(" 姓名: ").strip() if not name: print(" ❌ 姓名不能为空") return phone = input(" 电话: ").strip() email = input(" 邮箱: ").strip() group = input(" 分组 (朋友/家人/同事/其他): ").strip() or "其他" contact_id = generate_id() contacts[contact_id] = { "name": name, "phone": phone, "email": email, "group": group, "created": datetime.now().strftime("%Y-%m-%d %H:%M:%S"), } save_contacts(contacts) print(f" ✅ 已添加: {name} (ID: {contact_id})")def search_contacts(contacts): """搜索联系人""" keyword = input("\n🔍 搜索关键词: ").strip().lower() if not keyword: return [] results = { cid: c for cid, c in contacts.items() if keyword in c["name"].lower() or keyword in c.get("phone", "") or keyword in c.get("email", "").lower() or keyword in c.get("group", "").lower() } return resultsdef display_contacts(contacts_dict, title="联系人列表"): """显示联系人列表""" if not contacts_dict: print(" 📭 暂无数据") return print(f"\n📋 {title}(共 {len(contacts_dict)} 人)") print("-" * 60) print(f" {'ID':8s} {'姓名':8s} {'电话':14s} {'邮箱':20s} {'分组':6s}") print("-" * 60) for cid, c in sorted(contacts_dict.items(), key=lambda x: x[1]["name"]): print(f" {cid:8s} {c['name']:8s} {c.get('phone',''):14s} {c.get('email',''):20s} {c.get('group',''):6s}") print("-" * 60)def edit_contact(contacts): """编辑联系人""" cid = input("\n✏️ 输入要编辑的 ID: ").strip() if cid not in contacts: print(" ❌ ID 不存在") return c = contacts[cid] print(f" 当前: {c['name']} | {c.get('phone','')} | {c.get('email','')}") name = input(f" 新姓名 (回车保持 '{c['name']}'): ").strip() phone = input(f" 新电话 (回车保持 '{c.get('phone','')}'): ").strip() email = input(f" 新邮箱 (回车保持 '{c.get('email','')}'): ").strip() group = input(f" 新分组 (回车保持 '{c.get('group','')}'): ").strip() if name: c["name"] = name if phone: c["phone"] = phone if email: c["email"] = email if group: c["group"] = group save_contacts(contacts) print(f" ✅ 已更新: {c['name']}")def delete_contact(contacts): """删除联系人""" cid = input("\n🗑️ 输入要删除的 ID: ").strip() if cid not in contacts: print(" ❌ ID 不存在") return name = contacts[cid]["name"] confirm = input(f" 确认删除 '{name}'?(y/n): ").strip().lower() if confirm == "y": del contacts[cid] save_contacts(contacts) print(f" ✅ 已删除: {name}")# ============ 统计功能 ============def group_stats(contacts): """按分组统计""" if not contacts: print(" 📭 暂无数据") return groups = {c.get("group", "未分组") for c in contacts.values()} stats = { g: len([c for c in contacts.values() if c.get("group", "未分组") == g]) for g in groups } print("\n📊 分组统计:") for group, count in sorted(stats.items(), key=lambda x: -x[1]): bar = "█" * count print(f" {group:8s} | {bar} ({count}人)")def export_csv(contacts): """导出为 CSV""" filename = "contacts_export.csv" with open(filename, "w", encoding="utf-8-sig", newline="") as f: writer = csv.writer(f) writer.writerow(["ID", "姓名", "电话", "邮箱", "分组", "创建时间"]) for cid, c in contacts.items(): writer.writerow([cid, c["name"], c.get("phone",""), c.get("email",""), c.get("group",""), c.get("created","")]) print(f" ✅ 已导出: {filename}")def import_csv(contacts): """从 CSV 导入""" filename = input(" CSV 文件名: ").strip() if not os.path.exists(filename): print(f" ❌ 文件不存在: {filename}") return count = 0 try: with open(filename, "r", encoding="utf-8-sig") as f: reader = csv.DictReader(f) for row in reader: cid = generate_id() contacts[cid] = { "name": row.get("姓名", ""), "phone": row.get("电话", ""), "email": row.get("邮箱", ""), "group": row.get("分组", "其他"), "created": datetime.now().strftime("%Y-%m-%d %H:%M:%S"), } count += 1 save_contacts(contacts) print(f" ✅ 已导入 {count} 条记录") except Exception as e: print(f" ❌ 导入失败: {e}")# ============ 主菜单 ============def show_menu(): """显示菜单""" print("\n" + "=" * 40) print("📇 通讯录管理系统") print("=" * 40) print(" 1. 查看全部 2. 添加联系人") print(" 3. 搜索 4. 编辑联系人") print(" 5. 删除联系人 6. 分组统计") print(" 7. 导出 CSV 8. 导入 CSV") print(" q. 退出")def main(): """主程序""" contacts = load_contacts() print(f"📂 已加载 {len(contacts)} 条联系人") while True: show_menu() choice = input("\n请选择 (1-8/q): ").strip() if choice == "1": display_contacts(contacts, "全部联系人") elif choice == "2": add_contact(contacts) elif choice == "3": results = search_contacts(contacts) display_contacts(results, "搜索结果") elif choice == "4": edit_contact(contacts) elif choice == "5": delete_contact(contacts) elif choice == "6": group_stats(contacts) elif choice == "7": export_csv(contacts) elif choice == "8": import_csv(contacts) elif choice == "q": save_contacts(contacts) print("👋 再见!数据已保存。") break else: print(" ❌ 无效选择")if __name__ == "__main__": main()
3. 阶段总结:Day13-Day20 回顾
| | |
|---|
| | |
| | *args/**kwargs、作用域、lambda、闭包 |
| | map/filter/reduce、zip/enumerate、sorted |
| | open、with、read/write、模式大全 |
| | try/except/else/finally、自定义异常 |
| | import、__name__、pip、requirements.txt |
| | |
| | |
🎓 函数与模块阶段毕业感言:8 天前,你学会了定义第一个函数。今天,你能写出完整的词频分析器、通讯录管理系统——用函数组织代码、用文件保存数据、用异常处理保证稳定、用推导式简化逻辑。从 Day 21 开始,我们将进入面向对象编程(OOP)的世界——用"类"和"对象"来思考和组织代码,这是从"写脚本"到"写工程"的关键一步。准备好了吗?🚀
🔮 预告: Day 21 类与对象 — class、__init__、self。编程思维的一次升级!