2、Python基础速通(上)

各位同学好,我是老张。在光学测试这行摸爬滚打十几年,从最早用LabVIEW写采集程序,到后来用C#搭上位机,再到如今全面转向Python——说实话,Python是我用过最顺手的工具。今天咱们就来聊聊Python的基础知识,这部分内容我会分成上下两篇来讲。

你可能会问:做镜头测试,为啥要学Python?我举个例子。去年有个项目,需要批量处理5000张MTF测试图。如果用Excel手动算,三天都搞不完。我用Python写了个脚本,半小时搞定。这就是Python的魅力——简单、高效、生态好。

本章核心知识点:变量与数据类型、字符串操作、列表与字典、条件判断与循环、函数定义与调用。这些是Python的"内功心法",后面所有自动化测试脚本都离不开它们。

Python基础速通(上)知识体系 Python 基础核心 变量与数据类型 字符串操作 列表与字典 条件判断与循环 函数定义与调用 int/float/str bool/None 切片/格式化 常用方法 增删改查 嵌套结构 if/elif/else for/while 参数/返回值 作用域

2.1 变量与数据类型

Python的变量声明,跟C语言完全不一样。你不用写 int a = 10,直接写 a = 10 就行。Python会自动推断类型。我第一次用Python时觉得这太随意了,后来发现——嗯,真香。

常用的数据类型就这几种:

类型写法示例说明
整数count = 100镜头数量、像素坐标
浮点数mtf_value = 0.85MTF值、焦距、光圈
字符串lens_name = "广角镜头"镜头型号、测试报告
布尔值is_pass = True测试结果通过/不通过
Noneresult = None表示空值,还没测到数据

我的小习惯:在写测试脚本时,我习惯用type()函数检查变量类型。特别是从文件读取数据时,经常发现读进来的是字符串而不是数字——这种坑我踩过不下十次。

# 实际项目中的例子:读取镜头参数
focal_length = "50"  # 从配置文件读进来的是字符串
print(type(focal_length))  # <class 'str'>

# 必须转换才能做数学运算
focal_length = float(focal_length)
print(focal_length * 2)  # 100.0

2.2 字符串操作

字符串操作在测试脚本里太常用了。生成报告、拼接文件路径、格式化输出——哪哪都离不开它。

先说字符串拼接。我见过很多新手用 + 号拼字符串,其实有更好的办法:

# 不推荐的方式
report = "镜头型号:" + lens_name + ",MTF值:" + str(mtf)

# 推荐的方式——f-string(Python 3.6+)
report = f"镜头型号:{lens_name},MTF值:{mtf:.2f}"
print(report)
# 输出:镜头型号:广角镜头,MTF值:0.85

字符串切片也很实用。比如从文件路径里提取文件名:

path = "D:/test_data/2024/MTF_广角镜头_001.csv"
# 提取文件名
filename = path.split("/")[-1]
print(filename)  # MTF_广角镜头_001.csv

# 提取型号部分
model = filename.split("_")[1]
print(model)  # 广角镜头

我曾经踩过的坑:用split()切分中文字符串时,如果字符串里有特殊符号(比如全角逗号、空格),很容易切错。建议先用replace()统一替换成半角符号再切分。

2.3 列表与字典

列表和字典是Python里最常用的两种数据结构。说白了,列表就是有序的"购物清单",字典就是带标签的"储物柜"。

先看列表——我经常用它来存一组测试数据:

# 存储多个镜头的MTF值
mtf_values = [0.82, 0.85, 0.79, 0.88, 0.81]

# 添加新数据
mtf_values.append(0.86)

# 遍历并计算平均值
total = 0
for val in mtf_values:
    total += val
avg = total / len(mtf_values)
print(f"平均MTF值:{avg:.3f}")

字典就更灵活了。每个镜头有多个属性,用字典存最合适:

# 一个镜头的完整测试数据
lens_data = {
    "型号": "GW-50mm",
    "焦距": 50.0,
    "MTF_中心": 0.85,
    "MTF_边缘": 0.72,
    "畸变": -0.3,
    "测试日期": "2024-01-15"
}

# 读取某个值
print(lens_data["MTF_中心"])  # 0.85

# 更新数据
lens_data["MTF_中心"] = 0.87

实际项目经验:我在做镜头批量测试时,会把所有镜头的测试结果放在一个列表里,列表的每个元素都是一个字典。这样既方便遍历,又能快速查找某个镜头的所有数据。

# 批量测试数据管理
all_lenses = [
    {"型号": "A001", "MTF": 0.85, "结果": "通过"},
    {"型号": "A002", "MTF": 0.72, "结果": "不通过"},
    {"型号": "A003", "MTF": 0.88, "结果": "通过"},
]

# 找出所有不通过的镜头
failed = [lens for lens in all_lenses if lens["结果"] == "不通过"]
print(failed)  # [{'型号': 'A002', 'MTF': 0.72, '结果': '不通过'}]

2.4 条件判断与循环

条件判断和循环,是让程序"活起来"的关键。没有它们,代码就是一条道走到黑。

条件判断最常用的场景就是测试结果判定:

mtf_value = 0.78
threshold = 0.80

if mtf_value >= threshold:
    print("测试通过")
elif mtf_value >= threshold * 0.9:
    print("边缘合格,需复测")
else:
    print("测试不通过")

循环嘛,说白了就是"重复干活"。我写测试脚本时,最常用的就是 for 循环:

# 批量处理100个镜头的测试数据
for i in range(1, 101):
    filename = f"lens_{i:03d}.csv"
    # 这里调用处理函数
    print(f"正在处理第{i}个镜头:{filename}")

我的建议range()函数里的步长参数很好用。比如每隔5个镜头抽检一次,可以写 range(0, 100, 5)。这种小技巧能省不少事。

2.5 函数定义与调用

函数就是把一段逻辑封装起来,给它起个名字,以后想用就调用这个名字。我写测试脚本时,会把每个测试项都写成独立的函数。

def calculate_mtf(image_path, frequency):
    """
    计算指定频率下的MTF值
    参数:
        image_path: 图像文件路径
        frequency: 空间频率(lp/mm)
    返回:
        mtf值(浮点数)
    """
    # 这里是MTF计算逻辑(简化版)
    # 实际项目中会调用OpenCV等库
    mtf_result = 0.85  # 假设计算结果是0.85
    return mtf_result

# 调用函数
result = calculate_mtf("test_image.bmp", 30)
print(f"30 lp/mm下的MTF值:{result}")

函数参数还有一些高级用法,我挑两个最常用的说说:

# 默认参数——省得每次都要传
def test_lens(model, threshold=0.80):
    print(f"测试镜头:{model},阈值:{threshold}")
    # 测试逻辑...

test_lens("GW-50mm")  # 使用默认阈值0.80
test_lens("GW-50mm", 0.85)  # 自定义阈值

# 返回值可以是多个
def analyze_image(path):
    mtf_center = 0.85
    mtf_edge = 0.72
    distortion = -0.3
    return mtf_center, mtf_edge, distortion

center, edge, dist = analyze_image("test.bmp")
print(f"中心MTF:{center},边缘MTF:{edge}")

我曾经犯过的错:函数的默认参数如果是一个可变对象(比如列表、字典),多次调用会共享同一个对象。比如 def test(data=[]),第二次调用时 data 里还留着第一次的数据。正确的做法是用 None 做默认值,函数内部再创建新列表。

好了,Python基础速通的上半部分就讲到这里。这些内容看起来简单,但都是后面写自动化测试脚本的基石。我建议你打开Python环境,把上面的代码都敲一遍。光看不练,等于白看。


专注资料整理