本文目录导读:

写好Python案例,关键在于“真实有用” + “易于理解” + “启发思考” ,很多初学者看教程时觉得懂了,但自己写不出来,就是因为案例太理论化或太抽象。
下面我按受众分类,结合具体的代码结构,给出写好Python案例的5个核心原则和3个不同层次的实战示例。
写好Python案例的5个核心原则
-
场景化(拒绝“为了写代码而写代码”)
- 坏例子: 写一个函数计算
a + b。 - 好例子: “写一个自动计算外卖满减优惠的程序,当订单金额满30减5,满50减12。”
- 效果: 读者会想“这个我遇到过”,从而产生代入感。
- 坏例子: 写一个函数计算
-
渐进式(从简单到复杂)
- 先给出核心逻辑(最简单版本),再逐步增加异常处理、性能优化、美观输出。
- 先实现“读取文件” → 再实现“跳过空行” → 再实现“支持大文件流式读取”。
-
可运行(贴出完整的、能跑起来的代码)
- 很多案例只贴了片段,导致读者报错,案例应该包含必要的
import、主函数入口(if __name__ == “__main__”)和示例调用。 - 甚至提供模拟数据(如
test_data.txt的内容),让读者无需准备环境就能运行。
- 很多案例只贴了片段,导致读者报错,案例应该包含必要的
-
有注释 + 有输出结果
- 代码块要注释关键步骤(Why),而不是注释“定义变量a”(What)。
- 必须展示运行结果,这能立刻验证代码的正确性,也给读者成就感。
-
教方法 > 教代码
- 解释“为什么用这个库不用那个”、“如果数据量变大该怎么改”。
- 好的案例是“授人以渔”,比如顺便教
pdb调试或logging的使用。
三大层次实战案例(附代码与解析)
案例 1:新手友好级 —— “自动生成周报目录”
目标: 练习文件操作、字符串处理、循环。
场景: 每周五要写周报,标题格式是 2024_Week_48_名称.md,写脚本一键生成下周的空白周报模板。
代码:
import os
from datetime import datetime, timedelta
def create_weekly_report(base_path: str = "./reports"):
"""自动创建下周的周报模板文件"""
today = datetime.now()
# 计算下周一的日期
next_monday = today + timedelta(days=(7 - today.weekday()))
week_num = next_monday.isocalendar()[1]
year = next_monday.year
# 文件名格式:2024_Week_48_周报.md
filename = f"{year}_Week_{week_num}_周报.md"
filepath = os.path.join(base_path, filename)
# 确保目录存在
os.makedirs(base_path, exist_ok=True)
# 周报模板内容
content = f"""# {year} 第{week_num}周 工作周报
## 本周工作内容
1.
2.
3.
## 遇到的问题与解决
1.
2.
## 下周计划
1.
2.
## 备注
"""
# 写入文件
with open(filepath, "w", encoding="utf-8") as f:
f.write(content)
print(f"✅ 周报已生成:{filepath}")
return filepath
if __name__ == "__main__":
create_weekly_report()
讲解关键点:
- 为什么用
isocalendar()而不是strftime("%W")?因为isocalendar符合国际标准,跨年时更准确。 exist_ok=True的作用。
案例 2:进阶实用级 —— “使用并发下载图片并显示进度条”
目标: 练习 requests、concurrent.futures、tqdm 进度条。
场景: 需要爬取某个图片网站上10张高清壁纸,下载很慢,要同时下载且看到进度。
代码:
import requests
from concurrent.futures import ThreadPoolExecutor, as_completed
from tqdm import tqdm
import os
# 模拟图片URL列表
urls = [
f"https://picsum.photos/800/600?random={i}" for i in range(10)
]
def download_one_image(url: str, save_dir: str) -> str:
"""下载单张图片并保存"""
try:
# 从URL中提取文件名
img_name = url.split("?")[-1] + ".jpg"
filepath = os.path.join(save_dir, img_name)
# 流式下载节省内存
response = requests.get(url, stream=True, timeout=10)
response.raise_for_status()
with open(filepath, "wb") as f:
for chunk in response.iter_content(chunk_size=8192):
f.write(chunk)
return f"✅ {img_name} 下载成功"
except Exception as e:
return f"❌ {url} 下载失败: {str(e)}"
def batch_download(urls: list, max_workers: int = 5):
"""并发下载并显示进度"""
save_dir = "./downloads"
os.makedirs(save_dir, exist_ok=True)
# 使用线程池
with ThreadPoolExecutor(max_workers=max_workers) as executor:
# 提交所有任务
future_to_url = {executor.submit(download_one_image, url, save_dir): url for url in urls}
# tqdm包装as_completed显示进度
for future in tqdm(as_completed(future_to_url), total=len(urls), desc="下载进度"):
result = future.result()
# 可以在这里打印详细结果或写入日志
# print(result)
if __name__ == "__main__":
batch_download(urls)
讲解关键点:
- 为什么用
ThreadPoolExecutor而不是multiprocessing?因为下载是I/O密集型,线程更轻量。 iter_content流式下载为什么比response.content更好?避免大图占满内存。tqdm与as_completed的配合:进度条实时更新。
案例 3:高级专业级 —— “简易数据管道 + 缓存 + 日志”
目标: 练习装饰器、缓存(functools.lru_cache)、可配置化、日志记录。
场景: 需要编写一个数据处理工具,从CSV读取销售数据,进行清洗、计算、汇总,要求:
- 已算过的结果不重复计算(缓存)。
- 支持不同的数据源(文件、API)。
- 自动记录处理日志。
代码:
import csv
import logging
import functools
from typing import List, Dict, Callable
# 配置日志
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler("pipeline.log"),
logging.StreamHandler()
]
)
logger = logging.getLogger("DataPipeline")
class DataProcessor:
"""可配置的数据处理管道"""
def __init__(self, source: str, cache_size: int = 128):
self.source = source
self.raw_data: List[Dict] = []
self.clean_data: List[Dict] = []
logger.info(f"初始化处理器,数据源: {source}")
def load_csv(self) -> 'DataProcessor':
"""加载CSV数据"""
try:
with open(self.source, "r", encoding="utf-8") as f:
reader = csv.DictReader(f)
self.raw_data = list(reader)
logger.info(f"成功加载 {len(self.raw_data)} 条原始数据")
except FileNotFoundError:
logger.error(f"文件未找到: {self.source}")
raise
return self # 返回self实现链式调用
@functools.lru_cache(maxsize=128)
def compute_total_sales(self, category: str) -> float:
"""计算指定类别的销售额(带缓存)"""
logger.debug(f"计算类别: {category} 的销售额")
total = 0.0
for row in self.clean_data:
if row.get("category") == category:
try:
total += float(row.get("amount", 0))
except ValueError:
logger.warning(f"数据格式异常: {row}")
logger.info(f"类别 '{category}' 销售额: {total}")
return total
def run_pipeline(self) -> 'DataProcessor':
"""执行完整的数据处理流程"""
logger.info("开始执行数据管道")
self.load_csv()
# 清洗:去除金额为空的行
self.clean_data = [row for row in self.raw_data if row.get("amount") and float(row["amount"]) > 0]
logger.info(f"清洗后剩余 {len(self.clean_data)} 条有效数据")
return self
if __name__ == "__main__":
# 生成示例数据(模拟)
with open("test_sales.csv", "w", newline="") as f:
writer = csv.writer(f)
writer.writerow(["category", "amount", "date"])
writer.writerow(["电子产品", 1200, "2024-01-01"])
writer.writerow(["日用品", 50, "2024-01-02"])
writer.writerow(["电子产品", 800, "2024-01-03"])
# 使用管道
processor = DataProcessor("test_sales.csv")
processor.run_pipeline()
# 计算(第一次运行会执行函数)
print(processor.compute_total_sales("电子产品")) # 输出:2000.0
# 第二次运行会使用缓存,速度极快,且不会重新计算
print(processor.compute_total_sales("电子产品")) # 输出:2000.0 (来自缓存)
# 查看缓存信息
print(f"缓存命中情况: {processor.compute_total_sales.cache_info()}")
讲解关键点:
- 链式调用(
return self)的设计模式。 functools.lru_cache的适用场景:计算密集且输入参数有限时。- 结构化日志(同时输出到文件和终端,不同级别控制)。
- 异常处理与防御性编程(
try,logger.warning)。
如何写出好的Python案例
| 维度 | 坏案例 | 好案例 |
|---|---|---|
| 开头 | 直接贴代码,无上下文 | 先讲“你想解决什么问题” |
| 代码 | 只有函数定义 | 包含 import、模拟数据、主函数入口 |
| 输出 | 无输出截图或文字 | 展示运行结果,甚至有对比 |
| 讲解 | 只讲语法(“这是for循环”) | 讲“为什么用for不用while”,“如果数据量大怎么办” |
| 没有延伸思考 | 给出改进方向(如“加入数据库支持”、挑战题) |
最后建议: 写案例时,想象你在教一个刚入门但爱思考的朋友,先让他运行成功(拿得到结果),再让他理解原理(知道为什么),最后让他能动手改进(留出扩展点),这就是最好的Python案例。