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

day25 python异常处理

目录

Python 的异常处理机制

核心概念

常见的异常处理结构

try-except

try-except-else

常见异常类型

SyntaxError(语法错误)

NameError(名称错误)

TypeError(类型错误)

ValueError(值错误)

IndexError(索引错误)

KeyError(键错误)

AttributeError(属性错误)

ZeroDivisionError(除零错误)

FileNotFoundError(文件未找到错误)

ModuleNotFoundError(导入错误)

使用 try-except 捕获异常

捕获 ZeroDivisionError

捕获 TypeError

try-except-else-finally 的综合应用

try-except-else

finally 子句

总结


在借助 AI 辅助编写代码的过程中,我们经常会遇到 try-except 异常处理模块。这是因为大部分大模型在后训练阶段都经过了强化学习训练,为了确保代码的正确运行,try-except 异常处理模块能够显著提高模型运行成功的概率。然而,在日常手动编写代码时,我们可能并不会频繁使用这种写法。因此,今天我们将深入探讨 Python 的异常处理机制,帮助大家更好地适应这种编程范式。

Python 的异常处理机制

Python 的异常处理机制为程序提供了强大的容错能力(fault tolerance)。当程序在运行时遇到意外情况(即异常)时,它不会直接崩溃,而是可以被设计成优雅地处理这些错误,并可能继续执行后续逻辑(如果设计允许)或以可控的方式结束。

当异常发生时,Python 会创建一个异常对象(exception object),通常是 Exception 类的子类实例。如果这段可能出错的代码位于 try 语句块中,程序流程会寻找并跳转到匹配的 except 语句块(如果存在)来处理这个异常。

核心概念

  • try:包含可能会引发异常的代码块。程序会首先尝试执行这里的代码。

  • except:如果 try 块中的代码确实引发了特定类型的异常(或者任何异常,如果未指定类型),则执行此代码块。

  • else(可选):如果 try 块中的代码没有发生任何异常,则执行此代码块。

  • finally(可选):无论 try 块中是否发生异常,总会执行此代码块(常用于资源清理)。

常见的异常处理结构

try-except

这是最基本的错误处理结构。

try:# 可能会引发异常的代码
except ExceptionType:  # 最好指定具体的异常类型,例如 ZeroDivisionError, FileNotFoundError# 当 try 块中发生 ExceptionType 类型的异常时执行的代码
except:  # 不推荐:捕获所有类型的异常,可能会隐藏bug# 当 try 块中发生任何其他未被前面 except 捕获的异常时执行的代码

逻辑说明:程序首先尝试执行 try 块中的代码。如果 try 块中的代码没有发生异常,则 except 块会被跳过,程序继续执行 try-except 结构之后的代码。如果 try 块中的代码发生了异常,Python 会查找与该异常类型匹配的 except 块。如果找到匹配的,则执行该 except 块中的代码,然后继续执行整个 try-except 结构之后的代码(除非 except 块中又引发了新异常或执行了 return/break/continue 等)。如果未找到匹配的 except 块,异常会向上传播。

类比:你可以把它看作是:“尝试做这件事,如果出错了(并且是特定类型的错误),就执行补救措施。”

try-except-else

try-except 的基础上增加了 else 子句。

try:# 可能会引发异常的代码
except ExceptionType:# 当 try 块中发生 ExceptionType 类型的异常时执行的代码
else:# 当 try 块中【没有】发生任何异常时执行的代码

逻辑说明:首先,执行 try 块中的代码。如果 try 块中发生异常,则会查找并执行匹配的 except 块,else 块不会被执行。如果 try 块中没有发生任何异常,则会跳过所有 except 块,然后执行 else 块中的代码。

与 if-else-elif 的区别(重要!)

  • if-elif-else 结构中,只有一个代码块会被执行(if 条件满足则执行 if 块;否则检查 elif,满足则执行 elif 块;否则执行 else 块)。

  • 而在 try-except-else 结构中:

    • 如果 try 成功:try 块的代码会执行,然后 else 块的代码也会执行。

    • 如果 try 失败:try 块中出错前的代码会执行,然后匹配的 except 块的代码会执行(else 块不会执行)。

更准确的理解else 子句中的代码是你希望在 try 块中的代码成功完成且没有引发任何异常之后才执行的代码。这通常用于分离“主要尝试的操作”和“操作成功后的后续步骤”,使得 try 块更聚焦于可能出错的部分。

一个简单的例子阐述 else 的作用

try:# 假设 result_operation() 是一个可能出错的操作value = result_operation()
except SomeError:print("操作失败,使用默认值。")value = default_value
else:# 只有当 result_operation() 成功时,才执行这里的代码print(f"操作成功,结果是: {value}。现在进行后续处理...")process_value_further(value)

如果把 process_value_further(value) 放在 try 块内,那么如果 process_value_further 本身也可能抛出 SomeError(或其他 try 块想要捕获的错误),它就会被意外捕获。else 块确保了只有在 try 块中的代码完全无误地执行完毕后,才会执行 else 块的内容。

常见异常类型

在日常开发中,我们经常会遇到以下几种异常:

SyntaxError(语法错误)

原因:代码不符合 Python 的语法规则,解释器在尝试解析代码时就会失败。这种错误在程序运行之前就会被检测到。

# 示例 a: 缺少冒号
# def my_function()
#     print("Hello")# 示例 b: 非法表达式
# x = 5 +
# print(x)

NameError(名称错误)

原因:尝试使用一个未被定义的变量、函数或对象的名称。

# 示例 a: 变量未定义
# print(some_undefined_variable)# 示例 b: 打错变量名
# print(my_lisst)  # 变量名拼写错误

TypeError(类型错误)

原因:对一个不支持该操作的数据类型执行了某个操作或函数。

# print("Age: " + 25)  # 字符串和整数
# my_number = 10
# my_number()  # 尝试像函数一样调用一个整数

ValueError(值错误)

原因:函数接收到的参数类型正确,但其值不合适或无效。

# my_string = "12.34.56"
# number = float(my_string)  # '12.34.56' 不是一个有效的浮点数表示

IndexError(索引错误)

原因:尝试访问序列(如列表、元组、字符串)中一个不存在的索引。

# data = ("apple", "banana")
# print(data[2])

KeyError(键错误)

原因:尝试访问字典中一个不存在的键。

# student_grades = {"math": 90, "science": 85}
# print(student_grades["history"])

AttributeError(属性错误)

原因:尝试访问一个对象没有的属性或方法。

# 示例 a
# a_string = "hello"
# print(a_string.length)  # 字符串长度用 len(a_string),不是 .length 属性# 示例 b
# import numpy as np
# arr = np.array([1, 2, 3])
# print(arr.non_existent_attribute)

ZeroDivisionError(除零错误)

原因:尝试将一个数字除以零。

# result = 10 / 0

FileNotFoundError(文件未找到错误)

原因:尝试打开一个不存在的文件(通常是在读模式下),或者路径不正确。

# import pandas as pd
# data = pd.read_csv("hh.csv")

ModuleNotFoundError(导入错误)

原因:尝试导入一个不存在的模块,或者模块存在但其中的特定名称找不到。可以通过安装库解决,如果是自定义模块,则需要配置好对应的路径。

# import hhh

使用 try-except 捕获异常

当代码出现错误时,程序会立即停止执行,并打印出一个“traceback”(回溯信息),这个信息非常重要,它会告诉你:

  • 错误类型(例如 NameError, TypeError

  • 错误发生的文件名和行号

  • 导致错误的那行代码

  • 错误的简要描述

接下来,我们用固定的语句来捕获这类错误。

捕获 ZeroDivisionError

print("--- 使用 try-except 捕获 ZeroDivisionError ---")
numerator = 10
denominator = 0try:print("尝试进行除法运算...")result = numerator / denominator  # 潜在的风险代码print(f"计算结果是: {result}")  # 如果上面出错,这行不会执行
except ZeroDivisionError:print("发生了一个除以零的错误!")result = "未定义 (除以零)"  # 可以给一个默认值或提示print(f"程序继续执行... 最终结果的记录为: {result}")

捕获 TypeError

print("--- 使用 try-except 捕获 TypeError ---")
x = "Total items: "
y = 5  # 假设这是一个从某处获取的数字try:print("尝试连接字符串和数字...")message = x + y  # 潜在的 TypeErrorprint(f"最终消息: {message}")
except TypeError:print("类型错误!不能直接将字符串和数字相加。")print("尝试将数字转换为字符串进行连接...")message = x + str(y)  # 修正操作print(f"修正后的消息: {message}")print(f"程序继续... 生成的消息是: {message}")

try-except-else-finally 的综合应用

try-except-else

else 子句中的代码只有在 try 块中的代码成功执行且没有引发任何异常之后才会执行。这有助于分离“主要尝试的操作”和“操作成功后的后续步骤”,使得代码更加清晰。

print("--- try-except-else 示例 ---")def safe_divide(a, b):print(f"\n尝试计算 {a} / {b}")try:result = a / bexcept ZeroDivisionError:print("错误:除数不能为零!")return None  # 或者其他表示失败的值except TypeError:print("错误:输入必须是数字!")return Noneelse:# 只有当 try 块中的 a / b 成功执行时,这里才会执行print("除法运算成功!")print(f"结果是: {result}")# 可以在这里进行基于成功结果的进一步操作print(f"结果的两倍是: {result * 2}")return result# 测试用例
safe_divide(10, 2)  # 成功
safe_divide(10, 0)  # ZeroDivisionError
safe_divide("10", 2)  # TypeError
safe_divide(20, "abc")  # TypeError

finally 子句

finally 子句中的代码无论 try 块中是否发生异常,也无论 except 块是否被执行,甚至无论 tryexcept 块中是否有 return 语句,它总会被执行。这个特性在资源管理中非常重要,例如:

  • 无论训练成功、失败还是中途被打断,都确保日志文件被正确关闭,避免数据丢失或文件损坏。

  • 确保计算资源在使用完毕后被释放,供其他进程或任务使用。

  • 关闭数据库连接。

  • 恢复全局状态或配置,如果程序在运行过程中修改了全局变量或配置文件,在异常处理结束后,需要恢复到之前的状态或配置。

  • 在机器学习和深度学习项目中,模型训练可能非常耗时,如果中途因为各种原因(OOM、手动中断、硬件故障)停止,我们希望记录下中断的状态,方便后续恢复。

在 ML/DL 项目中,由于流程长、资源消耗大、外部依赖多,finally 提供的这种“保证执行”的机制对于构建稳定、可靠的系统至关重要。

总结

希望能够更好地理解 Python 的异常处理机制,并学会如何使用 try-excepttry-except-elsetry-except-else-finally 来编写更加健壮的代码。在日常开发中,我们不应该总是依赖 AI 来解决错误,而是要学会通过阅读错误信息来定位和解决问题,这样才能真正提升自己的编程能力。

@浙大疏锦行

http://www.xdnf.cn/news/451765.html

相关文章:

  • c#中equal方法与gethashcode方法之间有何关联?
  • 2025五一杭州西湖三天游
  • 大涡模拟实战:从区域尺度到街区尺度的大气环境模拟
  • 【python】UnicodeDecodeError: ‘gbk‘ codec can‘t decode byte 0xb2
  • 一种资源有限单片机处理cJSON数据的方法
  • 编写第一个MCP Client之Hello world
  • Android RTL语言视图适配(保加利亚,阿拉伯语种等)
  • JAVA中的文件操作
  • sqli—labs第六关——双引号报错注入
  • BitMart合约交易体验 BitMart滑点全赔的底层逻辑
  • 朱老师,3518系列,第八季
  • 使用Git+Cron实现BIND的Named域名配置自动化管理!
  • D2203使用手册—高压、小电流LDO产品4.6V~36V、150mA
  • AD 异性铺铜
  • 破解商业综合体清洁管理困局:商业空间AI智能保洁管理系统全场景解决方案
  • CodeBuddy 接入 MCP,一键生成网站!
  • 从规则驱动到深度学习:自然语言生成的进化之路
  • SpringbBoot nginx代理获取用户真实IP
  • 3337|3335. 字符串转换后的长度 I(||)
  • leetcode2934. 最大化数组末位元素的最少操作次数-medium
  • 练习小项目:倒数日小工具
  • Windows软件插件-写wav
  • 【Embedding Models】嵌入模型选择指南
  • 蓝卓入选2025宁波最具潜力新品牌TOP10
  • 数据库字段唯一性修复指南:从设计缺陷到规范实现
  • 安装windows版本的nacos
  • 总结下Jackson 中的JsonNode,ObjectNode,ArrayNode的方法
  • 时代推动建筑管理变革,楼宇自控系统成现代建筑管理必由之路
  • 数据结构·字典树
  • 每周靶点:TREM2、DLL3及文献分享