当前位置:首页 > Python 工业工具 > 正文内容

函数与模块:学会"一次写好,到处用"

函数与模块:学会"一次写好,到处用"

一、问题背景:为什么同样的事要做50遍?

刚做FAB数据分析时,我有一段痛苦的经历。

每个Lot的膜厚数据都需要算均值和标准差。当时我的代码是这样的:

```python

Lot A

data_a = [1250.5, 1248.3, 1251.2]

avg_a = sum(data_a) / len(data_a) # 算均值

diff_a = [(x - avg_a)**2 for x in data_a]

std_a = (sum(diff_a) / len(diff_a))**0.5 # 算标准差

print(f"Lot A: 平均={avg_a:.1f}, 标准差={std_a:.2f}")

Lot B

data_b = [1245.2, 1252.1, 1247.8]

avg_b = sum(data_b) / len(data_b)

diff_b = [(x - avg_b)**2 for x in data_b]

std_b = (sum(diff_b) / len(diff_b))**0.5

print(f"Lot B: 平均={avg_b:.1f}, 标准差={std_b:.2f}")

Lot C...D...E... 同样的代码重复几十遍

```

后面来了50个Lot。我复制粘贴了50遍。

每天8小时,4小时在按Ctrl+C、Ctrl+V。

问题是:如果均值公式要改(比如改成加权平均),要改50个地方。漏一个就bug。

学完这一篇,你能做到:

1. 用函数把重复代码打包成"一个公式"

2. 把函数存到单独的.py文件里,以后任何项目直接调用

3. 代码行数减少80%,bug数减少99%

---

二、技术原理:函数就是"计算公式"

2.1 一个最简单的函数

```python

定义函数:把"算均值"这个操作打包

def calc_avg(data):

"""计算平均值"""

return sum(data) / len(data)

使用函数——一行搞定

avg_a = calc_avg([1250.5, 1248.3, 1251.2])

avg_b = calc_avg([1245.2, 1252.1, 1247.8])

avg_c = calc_avg([1251.0, 1249.5, 1250.8])

print(avg_a, avg_b, avg_c)

```

看,不用再写 `sum(data) / len(data)` 了。每次要算均值,敲一行 `calc_avg()` 就完事。

同样,算标准差也打包:

```python

def calc_std(data):

"""计算样本标准差"""

avg = sum(data) / len(data)

variance = sum((x - avg)**2 for x in data) / (len(data) - 1)

return variance ** 0.5

print(calc_std([1250.5, 1248.3, 1251.2]))

```

现在要改什么? 只需要改 calc_avg 或 calc_std 里面的一行,所有用到它们的地方自动生效。

2.2 参数帮你"调出不同结果"

函数可以接受参数,让同样的算法适应不同的需求:

```python

def calc_avg(data, rounding=1):

"""

计算平均值,支持指定小数位

参数:

data: 数据列表

rounding: 保留几位小数(默认1位)

"""

raw = sum(data) / len(data)

return round(raw, rounding)

不同精度需求

print(calc_avg([1250.5, 1248.3])) # 保留1位: 1249.4

print(calc_avg([1250.5, 1248.3], 3)) # 保留3位: 1249.400

```

2.3 return和print有什么区别?

```python

❌ 错误:只用print,结果不能用

def calc_avg_bad(data):

print(sum(data) / len(data)) # 只是打印出来,没法赋值

result = calc_avg_bad([1, 2, 3]) # 打印 2.0

print(result) # None —— 空!因为没有return

✅ 正确:用return返回

def calc_avg_good(data):

return sum(data) / len(data) # 返回结果

result = calc_avg_good([1, 2, 3]) # result = 2.0

print(result * 10) # 20.0 —— 可以继续用

```

核心区别:`print` 是给肉眼看的,`return` 是给代码接着用的。函数一定要有 `return` 才能把结果传给后面的逻辑。

---

三、实战案例:搭建你的数据分析工具模块

3.1 把函数写到另一个文件里

打开IDE,新建一个文件 `fab_stats.py`:

```python

===== fab_stats.py =====

"""FAB数据统计工具包——一次写好到处用"""

def calc_avg(data):

"""计算平均值"""

if len(data) == 0: # 防止除零错误

return 0

return sum(data) / len(data)

def calc_std(data):

"""计算样本标准差"""

n = len(data)

if n < 2:

return 0

avg = calc_avg(data)

variance = sum((x - avg)**2 for x in data) / (n - 1)

return variance ** 0.5

def find_outliers(data, sigma=3):

"""

用3-sigma规则找异常值

参数:

data: 数据列表

sigma: 标准差倍数(默认3,调小更敏感)

返回:

list: 异常值的列表

"""

avg = calc_avg(data)

std = calc_std(data)

ucl = avg + sigma * std

lcl = avg - sigma * std

return [x for x in data if x > ucl or x < lcl]

def cpk(data, usl, lsl):

"""

计算工艺能力指数Cpk

参数:

data: 测量值列表

usl: 规格上限

lsl: 规格下限

"""

avg = calc_avg(data)

std = calc_std(data)

if std == 0:

return 0

cpu = (usl - avg) / (3 * std)

cpl = (avg - lsl) / (3 * std)

return min(cpu, cpl)

```

保存。然后在另一个文件里用:

```python

===== my_analysis.py =====

from fab_stats import calc_avg, calc_std, find_outliers, cpk

读取一批膜厚数据

thickness = [1250.5, 1248.3, 1251.2, 1249.8, 1250.1,

1247.5, 1250.8, 1249.1, 1251.5, 1248.2]

avg = calc_avg(thickness)

std_val = calc_std(thickness)

bad_vals = find_outliers(thickness)

c = cpk(thickness, usl=1253, lsl=1247)

print(f"均值={avg:.2f}, 标准差={std_val:.2f}")

print(f"异常值: {bad_vals}")

print(f"Cpk={c:.3f}")

```

3.2 再加个条件判断——区分异常Lot

```python

def check_lot(thickness_data, lot_id="Unknown"):

"""

判断一批Lot是否合格

返回:

dict: 包含所有分析指标的字典

"""

avg = calc_avg(thickness_data)

std = calc_std(thickness_data)

outliers = find_outliers(thickness_data)

c = cpk(thickness_data, usl=1253, lsl=1247)

# 判定标准:没有异常值 且 Cpk >= 1.0

passed = (len(outliers) == 0) and (c >= 1.0)

return {

"lot_id": lot_id,

"avg": avg,

"std": std,

"outlier_count": len(outliers),

"cpk": c,

"pass": passed

}

批量检查

all_lots = [

{"id": "A001", "data": [1250.5, 1248.3, 1251.2]},

{"id": "A002", "data": [1245.2, 1252.1, 1200.0]}, # 有异常

{"id": "A003", "data": [1251.0, 1249.5, 1250.8]},

]

for lot in all_lots:

result = check_lot(lot["data"], lot["id"])

status = "✅ 合格" if result["pass"] else "⚠ 不合格"

print(f"{result['lot_id']}: {status} "

f"(平均={result['avg']:.1f}, "

f"异常={result['outlier_count']}个, "

f"Cpk={result['cpk']:.2f})")

```

---

四、效果对比

| 对比维度 | 复制粘贴 | 用函数+模块 | 提升 |

|---------|---------|------------|------|

| 分析50个Lot | 复制50次(40分钟) | 1次循环(2秒) | 1200倍 |

| 改计算逻辑 | 改50处(30分钟) | 改1处(1分钟) | 30倍 |

| 代码行数 | 800+行 | 60行 | -92% |

| 调试难度 | 找bug像大海捞针 | 每个函数可单独测试 | 省心 |

| 新项目复用 | 重写 | `from fab_stats import *` | 秒用 |

---

五、自己动手

```python

练习:把你的工序数据做成模块

步骤1:新建一个 fab_thickness.py 文件

在里面写上:

def calc_avg(data): ...

def calc_range(data): ... # 计算极差 max - min

def check_thickness(data, target, tolerance): ...

步骤2:在另一个文件里 import 它

from fab_thickness import check_thickness

步骤3:批量检查一批数据

```

思考题

1. 为什么 `return` 比 `print` 重要?试试把函数里的return改成print,看看能不能赋值

2. 模块文件里的函数怎么加注释?加上 `"""文档字符串"""` 试试

3. 如果模块文件和主文件不在同一个文件夹,怎么import?(提示:用 `sys.path` 或者建包)

---

六、常见误区

| 错误 | 后果 | 解决方法 |

|------|------|---------|

| 函数名和变量名重复 | 变量覆盖了函数 | 用不同名字 |

| 忘了return | 返回None | 每个函数确保有return |

| 全局变量改来改去 | 改到哪乱了都不知道 | 尽量用参数传值 |

| 一个函数做太多事 | 测试困难,修改麻烦 | 一个函数只做一件事 |

一句话总结看到重复代码3次以上,立刻改成函数。

---

> 💬 你那有没有"复制粘贴到崩溃"的经历?评论区聊聊

> 📚 收藏+点赞,下一篇讲文件读写——把数据存起来 👆

相关文章

FAB工程师学Python的正确路径(附学习地图)

FAB工程师学Python的正确路径(附学习地图)

FAB工程师学Python的正确路径(附学习地图) 我带过一个实习生,非科班出身,学了3个月Python,第一个月工资就涨了2000。 也有干了5年的工艺工程师,手动导数据画图画了5年,月薪还是那点钱...

Python+半导体数据工具完整自学路线(零基础→项目实战)

Python+半导体数据工具完整自学路线(零基础→项目实战)

Python+半导体数据工具完整自学路线(零基础→项目实战) 经常有人问我:我想学Python做FAB数据分析,从哪里开始? 今天我把完整路线画出来,从零基础到能独立做项目,按这个走,90天能出师。...

Python日报自动化:MES数据一键生成Excel报告(附完整源码)

Python日报自动化:MES数据一键生成Excel报告(附完整源码)

Python日报自动化:MES数据一键生成Excel报告(附完整源码) 1. 我的血泪史:每天2小时的日报工作 2018年,我在FAB做整合工程师的时候,每天早上第一件事不是分析数据,而是做日报。从M...

Python设备故障预测:XGBoost让FAB的设备维护从被动到主动

Python设备故障预测:XGBoost让FAB的设备维护从被动到主动

Python设备故障预测:XGBoost让FAB的设备维护从被动到主动 1. 问题背景:被动维修的代价 FAB里最贵的不是设备,是设备宕机造成的产能损失。一台光刻机价值$100M+,停机1小时损失约$...

Python晶圆良率分析实战:从数据清洗到可视化(附完整代码)

Python晶圆良率分析实战:从数据清洗到可视化(附完整代码)

Python晶圆良率分析实战:从数据清洗到可视化(附完整代码) 1. 问题背景:我的第一次良率分析 2016年,我在FAB做工艺工程师的时候,第一次被要求分析一批良率异常。工程师把数据发给我——一个E...

工艺工程师学Python的6个正确姿势:别再走弯路了

工艺工程师学Python的6个正确姿势:别再走弯路了

工艺工程师学Python的6个正确姿势:别再走弯路了 1. 工艺工程师学Python的特殊性 工艺工程师学Python不是为了写程序,是为了解决工作中的问题。这个区别很重要:软件工程师追求代码漂亮,工...