📘 Day 31 实战作业:工程化规范 ------ 拆分与注解
1. 作业综述
核心目标:
- 拒绝"面条代码" :学会将一个巨大的脚本拆分成职责单一的多个
.py文件(如数据处理、模型定义、训练循环)。 - 提升可读性 :掌握 Python 的 Type Hinting (类型注解),明确告诉调用者每个参数是什么类型,返回值是什么类型。
涉及知识点:
- Type Hints :
List,Dict,Optional,Union的使用。 - File Splitting : 使用
%%writefile模拟创建dataset.py和model.py。 - Integration : 在
main.py中组装各个模块。
场景类比:
- 不拆分:像是在自家厨房做饭,调料、菜刀、锅碗瓢盆全堆在灶台上,乱但能用。
- 拆分后:像是五星级酒店后厨,切配间(Dataset)、烹饪间(Model)、摆盘间(Utils)严格分开,井井有条。
步骤 1:给代码加上"说明书" (Type Hinting)
场景描述 :
Python 是动态类型语言,这虽然方便,但也是大型项目的噩梦(你永远不知道 data 到底是一个列表还是一个字典)。
从 Python 3.5 开始,我们可以通过 类型注解 来规范代码。
任务:
- 引入
typing模块。 - 定义一个函数
process_batch,接收:batch_data: 一个包含浮点数的列表 (List[float])。threshold: 阈值,浮点数,默认 0.5 (float)。mode: 模式,字符串,可选 (str)。
- 返回值:一个字典,键是字符串,值是布尔值 (
Dict[str, bool])。 - 编写代码并测试。
py
from typing import List, Dict, Optional, Union
# 带有类型注解的函数
def process_batch(
batch_data: List[float],
threshold: float = 0.5,
mode: str = 'strict'
) -> Dict[str, bool]:
"""
模拟处理一批数据
"""
print(f"🔄 [Mode: {mode}] 正在处理 {len(batch_data)} 条数据...")
results = {}
for i, val in enumerate(batch_data):
# 逻辑:判断是否超过阈值
is_pass = val > threshold
results[f"sample_{i}"] = is_pass
return results
# --- 测试调用 ---
# 现在的 IDE (如 VSCode) 鼠标悬停在函数上时,会清晰显示参数类型
data = [0.1, 0.6, 0.8, 0.3]
res = process_batch(data, threshold=0.4)
print(f"处理结果: {res}")
# 验证注解只是提示,不会强制报错(Python 特性)
# 但好的工程师会严格遵守
process_batch([1, 2], mode="fast")
🔄 [Mode: strict] 正在处理 4 条数据...
处理结果: {'sample_0': False, 'sample_1': True, 'sample_2': True, 'sample_3': False}
🔄 [Mode: fast] 正在处理 2 条数据...
{'sample_0': True, 'sample_1': True}
步骤 2:模拟项目拆分 ------ 创建功能模块
场景描述 :
我们要构建一个微型的机器学习项目,包含两个核心模块:
dataset.py: 负责数据的加载和预处理。metrics.py: 负责计算准确率等指标。
任务 :
利用 %%writefile 分别创建这两个文件,并给它们内部的函数加上类型注解。
py
%%writefile dataset.py
from typing import List, Tuple
import random
def load_data(num_samples: int) -> List[Tuple[float, int]]:
"""
模拟加载数据
返回: [(特征, 标签), (特征, 标签)...]
"""
print(f"📦 [Dataset] 正在加载 {num_samples} 条数据...")
data = []
for _ in range(num_samples):
feature = random.random()
label = 1 if feature > 0.5 else 0
data.append((feature, label))
return data
Writing dataset.py
步骤 3:组装流水线 (main.py)
场景描述 :
有了零件(Modules),现在我们需要一个总指挥来把它们串起来。
通常这个文件叫 main.py 或 train.py。
任务:
- 创建一个
main.py。 - 导入
dataset和metrics模块。 - 编写一个
Model类(模拟)。 - 在
if __name__ == "__main__":中执行完整的训练评估流程。
py
%%writefile main.py
import dataset
import metrics
import random
from typing import List
class SimpleModel:
def predict(self, features: List[float]) -> List[int]:
# 模拟预测:简单的阈值判断
return [1 if f > 0.5 else 0 for f in features]
def run_pipeline():
# 1. 加载数据 (来自 dataset 模块)
raw_data = dataset.load_data(num_samples=20)
# 拆分特征和标签
features = [d[0] for d in raw_data]
labels = [d[1] for d in raw_data]
# 2. 模型预测
model = SimpleModel()
preds = model.predict(features)
# 3. 计算指标 (来自 metrics 模块)
acc = metrics.calculate_accuracy(labels, preds)
print(f"\n✅ 流程结束!模型准确率: {acc:.2%}")
if __name__ == "__main__":
run_pipeline()
Writing main.py
🎓 Day 31 总结:像架构师一样思考
今天我们没有学习新的算法,但学到了比算法更重要的东西 ------ 代码架构。
- 类型注解 (Type Hinting):它是你和团队(包括未来的自己)沟通的桥梁。养成写注解的习惯,能减少 50% 的调试时间。
- 模块化拆分 :将
dataset,model,train分离,是所有深度学习框架(PyTorch, TensorFlow)的标准范式。
Next Level :
至此,我们的 Python 基础与工程化特训彻底通关!
现在,你已经具备了阅读 GitHub 上那些成千上万星标项目(如 HuggingFace Transformers, YOLOv8)源码的能力。
去吧,去征服更广阔的 AI 世界!🚀