3、Python基础回顾(上):数据类型与结构、控制流、函数与异常处理
各位同学好,我是老赵。今天咱们聊聊Python基础,这部分内容虽然基础,但却是整个SIL自动化测试框架的基石。你想想看,如果连数据类型都搞不清楚,后面写测试脚本肯定会踩坑。我这些年带团队,发现很多问题其实都出在最基础的地方。
3.1 数据类型与结构:选对容器,事半功倍
Python的数据类型,说白了就是用来装数据的容器。我个人习惯把常用的四种结构——list、dict、set、tuple——叫做「四大金刚」。它们各有各的脾气,用对了地方,代码写起来特别顺手。
3.1.1 List(列表):最灵活的序列
List是Python里最常用的数据结构,没有之一。它支持增删改查,还能嵌套。我在项目中经常用它来存储测试用例的集合。
# 定义一个测试用例列表
test_cases = ["CAN_001", "CAN_002", "LIN_001"]
test_cases.append("ETH_001") # 追加
test_cases.insert(1, "CAN_003") # 插入
print(test_cases[0]) # 索引访问
3.1.2 Dict(字典):键值对的最佳拍档
Dict是另一种我几乎每天都要用的结构。它通过键来查找值,速度非常快。我曾经在项目中用dict来存储信号映射表,比如把CAN信号的ID映射到物理值上。
# 信号映射字典
signal_map = {
"0x123": "EngineSpeed",
"0x456": "VehicleSpeed",
"0x789": "BrakeStatus"
}
print(signal_map["0x123"]) # 输出:EngineSpeed
3.1.3 Set(集合):去重与关系运算
Set的特点是无序且元素唯一。我在做测试数据清洗时特别喜欢用它。比如从一堆报文ID中找出重复的,或者求两个测试集合的交集。
# 去重示例
raw_ids = [0x100, 0x200, 0x100, 0x300]
unique_ids = set(raw_ids)
print(unique_ids) # 输出:{0x200, 0x100, 0x300}
# 集合运算
set_a = {0x100, 0x200}
set_b = {0x200, 0x300}
print(set_a & set_b) # 交集:{0x200}
3.1.4 Tuple(元组):不可变的序列
Tuple和list很像,但一旦创建就不能修改。我一般用它来存储固定配置,比如某个测试环境的IP地址和端口号,因为这些东西不应该被意外修改。
# 固定配置
server_config = ("192.168.1.100", 8080)
ip, port = server_config # 解包
| 结构 | 可变性 | 有序性 | 常用场景 |
|---|---|---|---|
| List | 可变 | 有序 | 动态数据集合 |
| Dict | 可变 | 无序(3.7+有序) | 键值映射 |
| Set | 可变 | 无序 | 去重、集合运算 |
| Tuple | 不可变 | 有序 | 固定配置 |
3.2 控制流:让代码有逻辑地跑起来
控制流就是告诉程序什么时候该做什么事。if、for、while这三个家伙,我几乎每天都在用。嗯,这里要注意,控制流写不好,代码就会像一团乱麻。
3.2.1 if条件判断
if语句用来做分支判断。我在写测试脚本时,经常用它来判断测试结果是否通过。
test_result = 85
if test_result >= 90:
print("测试通过")
elif test_result >= 70:
print("测试需复查")
else:
print("测试失败")
3.2.2 for循环:遍历的利器
for循环用来遍历任何可迭代对象。我个人习惯用for来处理列表、字典等结构。
# 遍历测试用例
test_list = ["TC001", "TC002", "TC003"]
for tc in test_list:
print(f"正在执行:{tc}")
# 遍历字典
signal_map = {"Speed": 100, "RPM": 3000}
for key, value in signal_map.items():
print(f"{key}: {value}")
3.2.3 while循环:条件驱动
while循环适合在不确定循环次数时使用。比如等待某个信号值达到预期。
# 等待信号值变化
signal_value = 0
while signal_value < 100:
signal_value = read_signal() # 假设这是读取信号的函数
time.sleep(0.1)
print("信号值已达标")
3.3 函数定义与作用域:模块化的基础
函数是代码复用的基本单元。我写测试框架时,会把每个测试步骤封装成函数,这样既清晰又便于维护。
3.3.1 函数定义
def calculate_checksum(data: bytes) -> int:
"""计算校验和"""
checksum = 0
for byte in data:
checksum ^= byte
return checksum
# 调用
result = calculate_checksum(b"\x01\x02\x03")
print(result)
3.3.2 作用域规则
Python的作用域遵循LEGB规则:Local、Enclosing、Global、Built-in。说白了,就是先找局部变量,再找外层函数变量,然后找全局变量,最后找内置变量。
global_var = "全局变量"
def outer():
enclosing_var = "外层变量"
def inner():
local_var = "局部变量"
print(local_var) # 局部
print(enclosing_var) # 外层
print(global_var) # 全局
inner()
outer()
3.4 异常处理机制:让程序更健壮
异常处理是测试脚本中必不可少的部分。你想想看,测试过程中什么意外都可能发生——网络断了、设备没响应、数据格式不对。如果没有异常处理,脚本可能直接崩溃。
3.4.1 try-except基本结构
try:
result = 10 / 0 # 会触发ZeroDivisionError
except ZeroDivisionError as e:
print(f"捕获到异常:{e}")
except Exception as e:
print(f"其他异常:{e}")
else:
print("没有异常时执行")
finally:
print("无论是否异常都执行")
3.4.2 自定义异常
在测试框架中,我经常自定义异常来区分不同的错误类型。
class TestTimeoutError(Exception):
"""测试超时异常"""
pass
class TestDataError(Exception):
"""测试数据异常"""
pass
# 使用
try:
raise TestTimeoutError("CAN报文超时")
except TestTimeoutError as e:
print(f"测试超时:{e}")
3.5 知识体系总览
下面这张图是我自己整理的Python基础知识结构,你可以把它当作学习地图。
好了,这一章的内容就到这里。记住,基础不牢,地动山摇。把这些数据类型、控制流、函数和异常处理练熟了,后面写SIL测试脚本就会得心应手。