3、Python基础速通(二):条件判断与循环、函数定义、文件读写操作、异常处理

好,咱们接着聊。上一节我们把Python的基本数据类型和容器过了一遍,算是把工具箱里的零件认全了。这一节,咱们要学的是怎么让这些零件动起来——说白了,就是让代码有脑子、有体力、还能自己处理烂摊子。

我个人习惯把这一章叫做「代码的三板斧」:判断、循环、函数。再加上文件读写和异常处理,基本上日常的数据处理工作,你就能独立上手了。我在储能项目里,80%的脚本都离不开这些基础结构。

Python基础速通(二) 条件判断 if / elif / else 循环 for / while / break / continue 函数定义 def / return / 参数 文件读写 open / read / write / with 异常处理 try / except / finally 实战应用 储能数据清洗脚本 自动化数据处理

3.1 条件判断:让代码有脑子

条件判断,说白了就是让代码学会「看情况办事」。你想想看,储能系统里判断电池温度是否过高、SOC是否越界,哪样离得开条件判断?

# 最基本的if结构
soc = 85  # 电池荷电状态,单位%

if soc > 80:
    print("SOC过高,建议停止充电")
elif soc > 60:
    print("SOC正常,继续充电")
else:
    print("SOC偏低,建议充电")

这里有个细节我想强调一下——Python用缩进来表示代码块,而不是花括号。我刚开始用Python时,经常因为缩进不对导致逻辑错误。嗯,这里要注意:同一层级的代码缩进必须一致,一般用4个空格。

我的小技巧: 在PyCharm或VS Code里,按Tab键会自动转成4个空格。千万别混用Tab和空格,否则你会被折磨疯的——我曾经在一个300行的脚本里排查缩进问题,花了整整半小时。

3.2 循环:让代码有体力

循环就是让代码反复干同一件事。处理储能数据时,经常要遍历几千几万条记录,手动操作不现实,循环就是干这个的。

3.2.1 for循环——最常用

# 遍历一个电池组的电压数据
voltages = [3.2, 3.5, 3.8, 4.1, 3.9]

for i, v in enumerate(voltages):
    print(f"第{i+1}节电池电压: {v}V")
    if v > 4.0:
        print("  ⚠️ 电压偏高,请关注")

enumerate这个函数我特别喜欢。它同时返回索引和值,省得你手动维护一个计数器。我在处理储能BMS数据时,经常用它来定位异常电芯的位置。

3.2.2 while循环——条件驱动

# 模拟电池充电过程
soc = 20
while soc < 100:
    soc += 5
    print(f"当前SOC: {soc}%")
    if soc >= 80:
        print("进入涓流充电模式")
        break  # 提前退出循环
避坑指南: 用while循环一定要确保条件最终会变成False,否则就是死循环。我曾经在写一个数据采集脚本时,忘了更新循环变量,结果程序跑了一整夜没停——第二天服务器CPU直接爆了。

3.3 函数定义:把代码打包成工具

函数就是把一段逻辑封装起来,给它起个名字,以后随时调用。说白了,就是造工具。

def calculate_energy(voltage, current, time_hours):
    """
    计算电池储能电量
    参数:
        voltage: 电压(V)
        current: 电流(A)
        time_hours: 时间(h)
    返回:
        能量(kWh)
    """
    energy = voltage * current * time_hours / 1000
    return energy

# 调用函数
result = calculate_energy(48, 100, 2)
print(f"储能电量: {result:.2f} kWh")

我个人习惯在写函数时,一定会加docstring(就是那个三引号注释)。为什么?因为三个月后你回头看自己的代码,如果没有注释,你根本想不起来这个函数是干嘛的。我在项目里吃过这个亏,现在养成了习惯。

函数设计原则:
  • 一个函数只做一件事——单一职责
  • 函数名要能看出功能——见名知意
  • 参数不要太多——超过3个考虑用字典
  • 尽量有返回值——方便链式调用

3.4 文件读写操作:和硬盘打交道

储能数据分析,数据从哪来?大部分是从文件来的。CSV、TXT、JSON,都是家常便饭。

3.4.1 读取文件

# 读取储能系统的日志文件
with open('bms_log.txt', 'r', encoding='utf-8') as f:
    content = f.read()
    print(content[:200])  # 只打印前200个字符

with语句是Python的上下文管理器,它会自动帮你关闭文件。我见过很多新手写代码,打开文件后忘了关,导致文件句柄泄漏。用with就永远不会出这个问题。

3.4.2 写入文件

# 保存处理后的数据
processed_data = [
    "2024-01-15, 3.52, 25.3",
    "2024-01-15, 3.48, 25.1",
    "2024-01-15, 3.55, 25.6"
]

with open('output.csv', 'w', encoding='utf-8') as f:
    f.write("时间,电压,温度\n")
    for line in processed_data:
        f.write(line + '\n')

print("数据已保存到 output.csv")
文件模式小贴士:
模式说明我常用的场景
'r'只读读取历史数据
'w'写入(覆盖)保存处理结果
'a'追加实时记录日志
'r+'读写修改配置文件

3.5 异常处理:给代码穿上防弹衣

程序跑着跑着出错了怎么办?直接崩溃?那肯定不行。异常处理就是给代码加一层保护。

try:
    # 尝试读取一个可能不存在的文件
    with open('sensor_data.csv', 'r') as f:
        data = f.read()
        print("数据读取成功")
except FileNotFoundError:
    print("文件不存在,请检查路径")
    # 这里可以创建默认文件或使用备用数据
except PermissionError:
    print("没有权限读取该文件")
except Exception as e:
    print(f"发生了未知错误: {e}")
finally:
    print("无论是否出错,这行都会执行")

为什么会需要finally?我举个例子:你在处理储能数据时,打开了一个数据库连接,不管处理成功还是失败,这个连接都得关闭。finally就是干这个的。

我曾经踩过的坑: 不要用空的except语句捕获所有异常。这样会隐藏真正的bug,让你找不到问题根源。正确的做法是:先捕获具体的异常类型,最后再用Exception兜底。

3.6 实战:储能数据清洗小脚本

把今天学的知识串起来,写一个实际能用的脚本。假设我们有一个电池温度记录文件,需要清洗掉异常值。

def clean_temperature_data(input_file, output_file, min_temp=10, max_temp=45):
    """
    清洗电池温度数据
    剔除超出合理范围(10°C ~ 45°C)的异常值
    """
    cleaned_records = []
    error_count = 0
    
    try:
        with open(input_file, 'r', encoding='utf-8') as f:
            for line_num, line in enumerate(f, 1):
                try:
                    temp = float(line.strip())
                    if min_temp <= temp <= max_temp:
                        cleaned_records.append(temp)
                    else:
                        error_count += 1
                        print(f"第{line_num}行数据异常: {temp}°C,已剔除")
                except ValueError:
                    error_count += 1
                    print(f"第{line_num}行数据格式错误: {line.strip()}")
        
        # 保存清洗后的数据
        with open(output_file, 'w', encoding='utf-8') as f:
            for temp in cleaned_records:
                f.write(f"{temp}\n")
        
        print(f"清洗完成!有效数据: {len(cleaned_records)}条,异常数据: {error_count}条")
        
    except FileNotFoundError:
        print(f"错误:找不到文件 {input_file}")
    except Exception as e:
        print(f"处理过程中发生错误: {e}")

# 调用函数
clean_temperature_data('battery_temp.txt', 'battery_temp_clean.txt')

这个脚本里,我把条件判断、循环、函数、文件读写、异常处理全用上了。你想想看,如果不用这些结构,纯手工处理几百兆的日志文件,那得干到猴年马月去?

本章核心要点:
  • 条件判断让代码能「看情况办事」——if/elif/else
  • 循环让代码能「反复干活」——for/while
  • 函数把逻辑「打包成工具」——def/return
  • 文件读写让数据「持久化」——open/with
  • 异常处理让程序「不崩溃」——try/except

好了,这一节的内容就到这。这些基础结构看着简单,但真正用好需要大量练习。我建议你找个真实的储能数据文件,试着写个清洗脚本跑一跑。遇到问题很正常,调试本身就是学习的过程。


专注资料整理