深色模式
第 13 章 · 动手项目:把知识串起来
本章目标
用 5 个小项目覆盖前 12 章的主要知识点,每个项目给出完整可运行代码、运行方式与预期输出。
项目 1:猜数字游戏(条件 + 循环 + 随机)
要求:程序随机想一个 1–100 的数,用户来猜,提示"大了/小了",猜中后告诉用户猜了几次。
python
import random
def guess_game():
answer = random.randint(1, 100)
times = 0
print("我想好了一个 1~100 的数字,你来猜!")
while True:
raw = input("请输入你的猜测:")
if not raw.isdigit():
print("请输入整数哦")
continue
guess = int(raw)
times += 1
if guess > answer:
print("大了 ↓")
elif guess < answer:
print("小了 ↑")
else:
print(f"猜中啦!答案是 {answer},你用了 {times} 次")
break
if times == 10:
print(f"次数用完了,答案是 {answer}")
break
if __name__ == "__main__":
guess_game()学到:while True + break、input 的类型转换、random.randint。
怎么跑:粘到 guess.py,命令行 python guess.py,跟着提示输入数字。 预期:输错了会提示"大了 ↓ / 小了 ↑",猜中后会打印"猜中啦!答案是 X,你用了 N 次";超过 10 次会告知答案。
项目 2:通讯录(字典 + JSON 持久化)
要求:能添加联系人、查看全部、按名字查询,数据保存在 contacts.json。
python
import json
from pathlib import Path
FILE = Path(__file__).parent / "contacts.json"
def load():
if not FILE.exists():
return {}
with FILE.open(encoding="utf-8") as f:
return json.load(f)
def save(data):
with FILE.open("w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=2)
def add(data):
name = input("姓名:").strip()
phone = input("电话:").strip()
if not name:
print("姓名不能为空")
return
data[name] = {"phone": phone}
save(data)
print(f"已保存:{name} -> {phone}")
def show(data):
if not data:
print("通讯录是空的")
return
for name, info in data.items():
print(f"{name:<8}{info['phone']}")
def main():
data = load()
actions = {"1": add, "2": show}
while True:
print("\n1 添加 2 查看全部 q 退出")
choice = input("请选择:").strip()
if choice == "q":
print("再见")
break
action = actions.get(choice)
if action:
action(data)
else:
print("没有这个选项")
if __name__ == "__main__":
main()学到:字典嵌套、json 读写、Path 定位文件、函数式菜单。
怎么跑:存成 contacts.py 运行,按 1 加人、2 看全部、q 退出;数据会写进同目录的 contacts.json。 预期:添加后看到 已保存:小明 -> 138xxxx;下次重新运行,之前加的人还在(这就是持久化)。
进阶:加"删除"和"修改",加"按名字模糊查询"。
项目 3:批量重命名 / 整理文件(pathlib)
要求:把某个目录下所有 .txt 文件按 文件_001.txt 的规则重命名。
python
from pathlib import Path
folder = Path(input("要整理的目录:").strip())
if not folder.is_dir():
print("目录不存在")
else:
files = sorted(folder.glob("*.txt"))
for i, f in enumerate(files, start=1):
new_name = f"{folder.name}_{i:03d}{f.suffix}"
target = f.with_name(new_name)
if target.exists():
print(f"跳过(已存在):{new_name}")
continue
f.rename(target)
print(f"{f.name} -> {new_name}")
print(f"共处理 {len(files)} 个文件")学到:glob、enumerate 生成编号、{i:03d} 补零格式化、重命名。
怎么跑:先复制一个测试目录,里面放 2–3 个 .txt,再运行,按提示输入目录路径(如 E:\test-rename)。 预期:每改一个打印一行 原名.txt -> 目录名_001.txt,最后打印 共处理 N 个文件。
⚠️ 这个脚本会真的改文件名,先拿测试目录练手。
⚠️ 改文件名前先备份,别对着重要目录跑。
进阶:改成"按修改日期分组到年月子目录",那就是一个小型整理工具。
项目 4:文本词频统计(字典 + 排序 + 文件读)
要求:读一个 .txt,统计出现最多的 10 个词/字,输出成表格。
python
import re
from collections import Counter
from pathlib import Path
path = Path(input("文本文件路径:").strip())
text = path.read_text(encoding="utf-8")
# 英文按单词统计,中文按字统计都可以;这里演示英文单词
words = re.findall(r"[A-Za-z']+", text.lower())
counter = Counter(words)
print(f"总词数:{sum(counter.values())},不同词:{len(counter)}")
print("-" * 30)
for word, n in counter.most_common(10):
print(f"{word:<15}{n:>5}")学到:正则提取、Counter.most_common、read_text、格式化输出。
怎么跑:准备一个英文 .txt(比如把一段英文说明存下来),运行后粘贴路径。 预期:先打印 总词数:...,不同词:...,然后一张表:左边单词、右边次数,按次数从多到少。
进阶:加上"停用词过滤"(the、a、is 等不计),支持传入多个文件。
项目 5:简易记账(类 + JSON + 异常)
要求:记录收入和支出,能查看余额和明细,数据存 ledger.json。
python
import json
from pathlib import Path
FILE = Path(__file__).parent / "ledger.json"
class Ledger:
def __init__(self):
self.records = []
self.load()
def load(self):
if FILE.exists():
with FILE.open(encoding="utf-8") as f:
self.records = json.load(f)
def save(self):
with FILE.open("w", encoding="utf-8") as f:
json.dump(self.records, f, ensure_ascii=False, indent=2)
def add(self, kind, amount, note=""):
if kind not in ("收入", "支出"):
raise ValueError("类型只能是 收入 / 支出")
if amount <= 0:
raise ValueError("金额必须大于 0")
self.records.append({"类型": kind, "金额": amount, "备注": note})
self.save()
@property
def balance(self):
return sum(
r["金额"] if r["类型"] == "收入" else -r["金额"]
for r in self.records
)
def report(self):
for r in self.records:
sign = "+" if r["类型"] == "收入" else "-"
print(f"{r['类型']} {sign}{r['金额']:.2f} {r['备注']}")
print(f"当前余额:{self.balance:.2f}")
def main():
ld = Ledger()
while True:
print("\n1 记一笔 2 看明细 3 看余额 q 退出")
c = input("选择:").strip()
if c == "1":
kind = input("类型(收入/支出):").strip()
try:
amount = float(input("金额:"))
except ValueError:
print("金额必须是数字")
continue
note = input("备注(可空):").strip()
try:
ld.add(kind, amount, note)
print("已记录")
except ValueError as e:
print(f"记录失败:{e}")
elif c == "2":
ld.report()
elif c == "3":
print(f"余额:{ld.balance:.2f}")
elif c == "q":
break
if __name__ == "__main__":
main()学到:类的封装、@property、自定义校验、异常 + 持久化组合。
怎么跑:存成 ledger.py 运行,菜单选 1 记一笔(类型写"收入"或"支出"+金额)。 预期:记录后能选 3 看到累计余额;输错类型或负数金额会提示失败而不是崩溃;数据落在 ledger.json。
13.1 做完这 5 个项目的收获
| 项目 | 用到的知识 |
|---|---|
| 猜数字 | 循环、条件、随机、输入校验 |
| 通讯录 | 字典、JSON 落盘、文件路径 |
| 批量改名 | 路径操作、循环、格式化 |
| 词频统计 | 文件读、正则、Counter |
| 简易记账 | 类、属性、异常、JSON |
能把它们写出来,说明你已经"会用 Python 了",而不是"学过 Python"。
13.2 综合练习(不给答案,自己设计)
- 待办清单(todo):添加、完成、删除、保存到文件。
- 把项目 2 的通讯录改成"用类实现"。
- 读一个目录下所有
.txt,合并成一个文件,并在每段前加文件名。 - 给项目 4 加上
tqdm进度条和导出 CSV 功能。