当前位置: 首页 > news >正文

Python程序设计强基计划10讲 · 第五讲:文件操作与异常处理——稳健编程的基石

Python程序设计强基计划10讲 · 第五讲:文件操作与异常处理——稳健编程的基石

作者:培风图南以星河揽胜
发布时间:2026年3月31日
适用对象:已掌握函数与模块机制的Python学习者
前置知识:第四讲《函数与模块——代码复用的艺术》
标签:Python文件操作、异常处理、上下文管理器、logging、CSDN博客


引言:为什么你的程序总在“关键时刻崩溃”?

你是否经历过以下场景?

  • 程序运行到一半,突然报错FileNotFoundError,所有中间结果丢失;
  • 用户输入了非法数据,程序直接退出,毫无提示;
  • 服务器日志一片空白,无法定位线上问题。

这些问题的根源,在于缺乏对不确定性的处理。现实世界充满意外:

  • 文件可能被删除、移动或权限不足;
  • 网络可能中断;
  • 用户输入永远不可信。

文件操作与异常处理,正是Python应对这些不确定性的核心机制。它们让你的程序从“脆弱脚本”蜕变为“健壮应用”。

本讲将带你系统掌握稳健编程的三大支柱

  1. 文件操作:安全读写文本/二进制数据,自动资源管理;
  2. 异常处理:优雅捕获错误,防止程序崩溃;
  3. 日志记录:追踪程序行为,助力问题诊断。

掌握这些,你写的程序将具备:

  • 不崩溃(Graceful Degradation)
  • 可恢复(Error Recovery)
  • 可追溯(Audit Trail)

一、文件操作:安全读写的艺术

1.1 基本文件操作流程

传统方式(不推荐):

f=open("data.txt","r")content=f.read()f.close()# 容易忘记!
⚠️ 风险:
  • f.read()抛出异常,f.close()不会执行 →资源泄漏
  • 手动管理资源违背“自动内存管理”的Python哲学。

1.2 上下文管理器(with语句):自动资源管理

推荐方式

withopen("data.txt","r",encoding="utf-8")asf:content=f.read()# 文件自动关闭,即使发生异常!
✅ 核心优势:
  • 自动调用__enter____exit__
  • 确保资源释放(文件、网络连接、锁等);
  • 代码更简洁、安全

黄金法则永远用with open,不用裸open()


1.3 文本文件 vs 二进制文件

模式说明示例
"r"/"w"/"a"文本模式(默认)open("file.txt", "r")
"rb"/"wb"/"ab"二进制模式open("image.jpg", "rb")
📌 关键区别:
  • 文本模式
    • 自动解码/编码(需指定encoding);
    • 换行符自动转换(\n\r\n)。
  • 二进制模式
    • 读写bytes对象;
    • 无任何转换,原样处理。
✅ 正确指定编码
# 必须指定 encoding,避免跨平台乱码withopen("data.txt","r",encoding="utf-8")asf:...

口诀“文本文件加 encoding,二进制文件用 rb/wb。”


1.4 常用读写方法

读取
方法返回值适用场景
f.read()整个文件字符串小文件
f.readline()单行字符串逐行处理
f.readlines()行列表需要随机访问行
写入
方法说明
f.write(string)写入字符串
f.writelines(lines)写入字符串列表(不自动加换行符!)
✅ 安全写入示例
lines=["Line 1\n","Line 2\n"]withopen("output.txt","w",encoding="utf-8")asf:f.writelines(lines)# 每行必须自带 \n

1.5 处理空行与无效数据

真实文件常包含:

  • 空行
  • 注释行(如# comment
  • 格式错误的数据
✅ 健壮读取模板
data=[]withopen("scores.txt","r",encoding="utf-8")asf:forlineinf:stripped=line.strip()# 去除首尾空白ifnotstripped:# 跳过空行continueifstripped.startswith("#"):# 跳过注释continuetry:score=int(stripped)data.append(score)exceptValueError:print(f"Warning: Invalid data '{stripped}', skipped.")

原则永远假设输入是脏的


二、异常处理:优雅应对错误

2.1 异常处理基础:try/except/else/finally

基本结构
try:# 可能出错的代码risky_operation()exceptSpecificErrorase:# 处理特定异常handle_error(e)exceptExceptionase:# 处理其他异常(兜底)log_error(e)else:# 无异常时执行success_action()finally:# 无论是否异常都执行(清理资源)cleanup()
🌰 实战示例:安全除法
defsafe_divide(a,b):try:result=a/bexceptZeroDivisionError:print("Error: Division by zero!")returnNoneelse:print("Division successful.")returnresultfinally:print("Cleanup done.")print(safe_divide(10,2))# 成功print(safe_divide(10,0))# 错误

2.2 常见内置异常类型

异常触发场景处理建议
FileNotFoundError文件不存在检查路径、提供默认值
PermissionError权限不足提示用户、降级操作
ValueError值无效(如int("abc")验证输入、友好提示
KeyError字典键不存在get()或预检查
IndexError列表索引越界检查长度、用try包裹
✅ 最佳实践:捕获具体异常,而非笼统的Exception
# 好try:withopen(filename)asf:...exceptFileNotFoundError:print(f"File{filename}not found.")# 坏(掩盖其他错误)try:withopen(filename)asf:...exceptException:print("Something went wrong.")# 无法定位问题!

2.3 自定义异常:表达业务逻辑错误

当内置异常不足以描述问题时,定义自己的异常类

✅ 创建自定义异常
classInvalidScoreError(ValueError):"""成绩不在有效范围 [0, 100]"""passdefvalidate_score(score):ifnot(0<=score<=100):raiseInvalidScoreError(f"Score{score}is invalid!")# 使用try:validate_score(150)exceptInvalidScoreErrorase:print(e)# Score 150 is invalid!

优势

  • 语义清晰;
  • 可被单独捕获;
  • 便于文档化。

2.4 异常链(Exception Chaining)

当捕获一个异常后抛出另一个异常时,保留原始异常信息。

✅ 使用raise ... from ...
defprocess_file(filename):try:withopen(filename)asf:returnf.read()exceptFileNotFoundErrorase:raiseRuntimeError(f"Failed to process{filename}")frome# 调用try:process_file("missing.txt")exceptRuntimeErrorase:print(e.__cause__)# 原始 FileNotFoundError

作用保留完整的错误上下文,便于调试。


三、日志记录(logging):程序的“黑匣子”

3.1 为什么不用print()

问题logging 解决方案
无法区分信息级别支持 DEBUG/INFO/WARNING/ERROR/CRITICAL
生产环境难关闭可配置输出目标(文件、网络等)
无时间戳、模块名自动添加元数据
性能差(字符串拼接)延迟求值(仅在需要时格式化)

3.2 logging 基础用法

✅ 快速开始
importlogging# 配置日志(通常在程序入口)logging.basicConfig(level=logging.INFO,format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',handlers=[logging.FileHandler("app.log"),logging.StreamHandler()# 同时输出到控制台])logger=logging.getLogger(__name__)# 使用logger.info("Application started.")logger.warning("This is a warning.")logger.error("An error occurred!")
输出示例:
2026-03-31 10:00:00,123 - __main__ - INFO - Application started. 2026-03-31 10:00:00,124 - __main__ - WARNING - This is a warning. 2026-03-31 10:00:00,125 - __main__ - ERROR - An error occurred!

3.3 日志级别与最佳实践

级别用途生产环境
DEBUG详细调试信息通常关闭
INFO程序正常流程开启
WARNING潜在问题开启
ERROR功能错误开启
CRITICAL严重错误,程序可能退出开启
✅ 最佳实践:
  • 模块级 loggerlogger = logging.getLogger(__name__)
  • 不要用print()记录程序状态
  • 敏感信息不记日志(如密码、身份证号)

3.4 在异常处理中使用日志

importlogging logger=logging.getLogger(__name__)defload_config(filename):try:withopen(filename)asf:returnjson.load(f)exceptFileNotFoundError:logger.error(f"Config file{filename}not found. Using defaults.")returnDEFAULT_CONFIGexceptjson.JSONDecodeErrorase:logger.critical(f"Invalid JSON in{filename}:{e}",exc_info=True)raise# 重新抛出,终止程序

关键参数exc_info=True自动记录完整 traceback


四、典型误区与避坑指南

误区1:忽略文件编码

# 危险!withopen("data.txt","r")asf:...

修正with open("data.txt", "r", encoding="utf-8") as f:

误区2:空 except 块

# 绝对禁止!try:risky_code()except:pass# 静默失败,bug 难以发现

修正:捕获具体异常,并记录日志

误区3:在 finally 中 return

# 危险!defbad_example():try:return"success"finally:return"cleanup"# 覆盖 try 中的 return!

修正:finally 仅用于清理,不返回值

误区4:日志字符串提前格式化

# 低效(即使日志级别不够也会格式化)logger.debug("Value: "+str(expensive_function()))# 高效(延迟求值)logger.debug("Value: %s",expensive_function())

五、动手练习:构建健壮程序

练习1:安全文件读取器

编写函数read_scores(filename)

  • 安全读取文件(处理FileNotFoundError);
  • 过滤空行和注释;
  • 转换每行为整数(处理ValueError);
  • 返回有效分数列表。

练习2:带日志的除法函数

编写函数logged_divide(a, b)

  • 使用 logging 记录操作;
  • 捕获ZeroDivisionError并记录错误;
  • 正常时记录结果。

练习3:自定义异常实战

定义异常EmptyFileError,在读取空文件时抛出。
编写函数process_nonempty_file(filename),若文件为空则抛出该异常。


六、本讲小结:稳健编程的三大支柱

  1. 文件操作:用with管理资源,指定编码,过滤脏数据;
  2. 异常处理:捕获具体异常,自定义业务异常,保留错误链;
  3. 日志记录:替代print(),分级记录,助力问题追溯。

关键口诀

  • “文件操作 with 走,编码指定不能漏。”
  • “异常处理要具体,日志分级助 debug。”
  • “程序不怕出错,怕的是静默崩溃。”

下期预告:第六讲《面向对象编程(OOP)入门——封装、继承与多态》

下一讲将开启Python的面向对象之旅:

  • 类与对象的基本概念
  • 封装:属性与方法的访问控制
  • 继承:代码复用的强大机制
  • 多态:接口统一的灵活性
    助你从“过程式思维”迈向“对象式思维”!

原创声明:本文为《Python程序设计强基计划10讲》系列第五讲,版权归作者所有。
互动邀请:你在处理文件或异常时踩过哪些坑?欢迎评论区分享经验!
关注我,系统提升Python工程能力,写出真正健壮的程序!

http://www.jsqmd.com/news/588747/

相关文章:

  • nvm安装node
  • 用python + pillow实现GUI界面图片GUI处理工具
  • Condition底层机制剖析:多线程等待与通知机制 _
  • 南北阁 Nanbeige 4.1-3B 企业应用实战:客服预研、内部知识问答、合规本地化部署案例
  • 认知 对抗性雷达推理:逆向跟踪、认知识别与智能干扰设计——MATLAB实现
  • GlusterFS深度解析
  • Zrythm未来路线图:AI集成、云端协作与下一代音频技术
  • 【C++第二十三章】C++11
  • Python程序设计强基计划10讲 · 第六讲:面向对象编程(OOP)入门——封装、继承与多态
  • ESP32-C3、ESP32-S3、ESP32-C6 应该怎么选:面向定制固件项目的芯片判断
  • 软测学习笔记|2026.4.1|流程|分类|项目经验
  • ReTerraForged地形生成模组安装与配置全指南
  • 即插即用系列 | AAAI 2026 | SACF:光谱引导自适应跨层融合,强化目标内相关性与纹理细节,特征更精准! | 代码分享
  • Nano-Banana多场景落地:从电商详情页到产品培训手册的视觉赋能
  • Python程序设计强基计划10讲 · 第七讲:标准库精要——高效开发的秘密武器
  • 4 大类别 22 个高效的 Agentic Skills | 适用于 Claude、GPT
  • python decimal
  • Linux系统堆与栈原理深度剖析
  • 2025最权威的降重复率网站解析与推荐
  • 【数据结构与算法】第25篇:静态查找(一):顺序查找与折半查找
  • 文件存储Minio学习指南
  • NumPy张量缩并怎么用_np.einsum()爱因斯坦求和约定高级索引魔法
  • CMake赋能持续集成|自动化测试落地的进阶指南 ✨
  • 收藏!从房价暴跌看风口:小白/程序员必抓的AI大模型红利,零基础也能逆袭
  • CSS知识概述
  • 2026届毕业生推荐的五大AI论文网站实际效果
  • text2vec-base-chinese中文语义向量实战指南
  • 大语言模型部署时怎么解决显存爆炸问题
  • AquaticCLIP: A Vision-Language Foundation Model and Dataset for Underwater Scene Analysis
  • 【豆包从入门到精通】001、初识豆包:大模型时代的入门钥匙