Skip to content

第 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 综合练习(不给答案,自己设计) ​

  1. 待办清单(todo):添加、完成、删除、保存到文件。
  2. 把项目 2 的通讯录改成"用类实现"。
  3. 读一个目录下所有 .txt,合并成一个文件,并在每段前加文件名。
  4. 给项目 4 加上 tqdm 进度条和导出 CSV 功能。

试图用自己的方式,重新定义属于我的人生