面向对象编程:把代码拆成"小方块"
面向对象编程:把代码拆成"小方块"
一、问题背景:2000行代码在一个文件里,改都不敢改
去年接手了一个数据分析工具。2000行代码,全在一个文件里,没有类、没有模块。
想改一个函数?不敢——因为全局变量被七八个函数共享,不知道改了取值会不会影响到其他地方。
想加一个功能?发现要在三个函数里分别加判断,缺一个就出Bug。
新同事来了,看了两天说:"这些数据怎么串来串去的?"
痛在哪里:数据和操作数据的函数是分开的。就像把扳手、螺丝、图纸全堆在一个大箱子里,找个东西要把所有东西都倒出来。
后来我用"类"重构了——把相关的数据和函数打包在一起,拆成几个小文件。每个文件300行,改起来心里有底了。
学完这一篇,你能做到:
1. 理解什么是"类"(把数据和函数打包)
2. 写一个简单的类,把数据分析和存储放在一起
3. 知道什么时候该用类、什么时候不用
---
二、技术原理:类就是"打包"
2.1 不用类的问题是代码散落
```python
不用类:数据和函数是散的
数据在这里
lot_1_id = "FAB-001"
lot_1_thickness = [1250.5, 1248.3, 1251.2]
lot_1_status = "pending"
lot_2_id = "FAB-002"
lot_2_thickness = [1247.5, 1250.8, 1249.1]
lot_2_status = "pending"
函数在那里
def analyze_lot(lot_id, data):
avg = sum(data) / len(data)
return {"id": lot_id, "avg": avg}
def mark_lot_done(lot_id):
# 怎么找到对应的变量?
pass # 不知道
```
随着Lot增多,代码越来越乱。
2.2 用类打包
```python
class LotData:
"""Lot数据类——把数据和操作打包在一起"""
def __init__(self, lot_id, thickness_data):
self.lot_id = lot_id
self.thickness = thickness_data
self.status = "pending" # pending/done/error
def analyze(self):
"""分析这批数据"""
avg = sum(self.thickness) / len(self.thickness)
std = (sum((x - avg)**2 for x in self.thickness) /
(len(self.thickness) - 1)) ** 0.5
return {"lot_id": self.lot_id, "avg": round(avg, 2), "std": round(std, 2)}
def mark_done(self):
"""标记完成"""
self.status = "done"
def summary(self):
"""打印摘要"""
print(f"[{self.lot_id}] 厚度数={len(self.thickness)}, 状态={self.status}")
```
2.3 使用这个类
```python
创建两个Lot
lot_a = LotData("FAB-001", [1250.5, 1248.3, 1251.2])
lot_b = LotData("FAB-002", [1247.5, 1250.8, 1249.1])
分析
result_a = lot_a.analyze() # 自己的数据自己分析
result_b = lot_b.analyze()
print(f"{lot_a.lot_id}: 平均={result_a['avg']}")
print(f"{lot_b.lot_id}: 平均={result_b['avg']}")
标记完成
lot_a.mark_done()
lot_a.summary() # [FAB-001] 厚度数=3, 状态=done
```
类和之前学的函数有什么区别? 函数是把"操作"打包,类是把"数据+操作"一起打包。`analyze` 函数需要你传数据进来,`LotData.analyze()` 方法直接用自己内部的数据——就像你给你的猫取个名字,猫就知道自己叫什么,不用每次都问。
---
三、实战案例:做一个设备监控类
```python
import time
import random
class Equipment:
"""FAB设备监控类"""
def __init__(self, equip_id, equip_type):
self.id = equip_id
self.type = equip_type
self.status = "IDLE"
self.temp = 25.0
self.pressure = 1.0
self.process_count = 0
def start_process(self, recipe="default"):
"""开始加工"""
if self.status == "RUNNING":
print(f"⚠ {self.id} 正在运行中")
return False
self.status = "RUNNING"
self.recipe = recipe
self.temp = 85.0 # 升温
self.pressure = 1.5
self.process_count += 1
print(f"✅ {self.id} 开始 [{recipe}] (已加工{self.process_count}次)")
return True
def stop(self):
"""停止"""
self.status = "IDLE"
self.temp = 25.0
self.pressure = 1.0
print(f"⏹ {self.id} 停止, 温度降至{self.temp}°C")
def check_temp(self):
"""检查温度是否异常"""
if self.temp > 100:
print(f"⚠ {self.id} 温度过高: {self.temp}°C!")
return False
return True
def report(self):
"""打印状态报告"""
print(f"=== {self.id} ({self.type}) ===")
print(f" 状态: {self.status}")
print(f" 温度: {self.temp}°C")
print(f" 压力: {self.pressure} torr")
print(f" 加工次数: {self.process_count}")
使用
etch = Equipment("ETCH-01", "刻蚀机")
cvd = Equipment("CVD-02", "沉积设备")
etch.report()
etch.start_process("OXIDE_ETCH") # 开始加工
etch.check_temp() # 检查温度
etch.stop() # 停止
cvd.start_process("SIN_DEP")
cvd.report()
```
为什么用类管理设备比用字典好? 如果用字典,你要写 `device['status'] = 'RUNNING'`,然后在另一个函数里 `if device['status'] == 'RUNNING'`——状态分散在代码各处,改了设备结构的某个字段名,所有用到的地方都要改。用类之后,状态和操作都在类内部,外面只调用 `etch.start_process()`,底层怎么实现你改里面就行,外面不用动。这就是"封装"的好处。
---
四、效果对比
| 维度 | 不用类(散装) | 用类打包 |
|------|--------------|---------|
| 数据位置 | 分散在各种变量里 | 在类内部统一管理 |
| 新增函数 | 加一个新函数要小心别影响了其他 | 加在类内部,自己管自己 |
| 阅读理解 | 看完整篇才知道数据怎么流动的 | 看一个类就知道 |
| 多人协作 | 容易互相覆盖变量 | 各自用各自的类 |
---
五、自己动手
```python
练习:做一个 LotTracker 类
功能:记录和分析一批Lot数据
class LotTracker:
def __init__(self, line="ETCH"):
self.line = line
self.lots = [] # 存放Lot数据
def add_lot(self, lot_id, thickness_avg):
"""添加一批Lot"""
self.lots.append({"id": lot_id, "avg": thickness_avg})
def total_count(self):
"""返回Lot总数"""
pass # ✏️ 你的代码
def avg_yield(self):
"""返回所有Lot的平均厚度"""
pass # ✏️ 你的代码
def summary(self):
"""打印统计报告"""
pass # ✏️ 你的代码
尝试使用
tracker = LotTracker("ETCH")
tracker.add_lot("A001", 1250.5)
tracker.add_lot("A002", 1248.3)
tracker.summary()
```
思考题:
1. 类和字典有什么区别?什么时候用类,什么时候用字典就够了?
2. `__init__` 为什么叫"初始化"?不写 `__init__` 行不行?
3. 类里可以有另一个类吗?(提示:嵌套类)
---
六、常见误区
| 问题 | 表现 | 正确做法 |
|------|------|---------|
| 啥都写成类 | 类套类,复杂死了 | 简单的逻辑用函数就够了 |
| 类太大了 | 一个类500行 | 拆成多个小类 |
| 属性在外面直接改 | `lot.status = 'xxx'` 全是硬编码 | 用方法 `lot.mark_done()` 来改 |
| 学了面向对象不会用 | 不知道什么场合用 | 发现数据散落各处的时候就用类 |
---
关于"面向对象"我多说几句
很多人学Python时被"面向对象"劝退了——太难了。
我的建议是:菜鸟阶段不用硬学。你写100行的脚本,用函数完全够了。当你发现:
- 一个功能改了、其他地方全崩了
- 代码超过500行,找变量定义要找半天
- 改了A功能、影响B功能
这个时候再回来学面向对象,一学就会——因为你有"需求"了。
---
> 💬 你用类写过什么项目?觉得类真的有用还是觉得花架子?
> 📚 收藏+点赞,下一篇开始做项目 👆





