Python 异常处理全攻略:try/except/else/finally、自定义异常、with 语句一文搞定
📌 程序运行时难免出错,Python 的异常处理机制让你优雅地应对错误,而不是让程序直接崩溃。本文系统梳理 Python 异常处理的核心知识点,从基础的 try/except 到自定义异常,配合丰富代码示例,适合初学者收藏学习。
📑 目录
- 一、异常是什么?
- 二、try/except 基础捕获
- 三、捕获指定类型异常
- 四、else:没有异常时执行
- 五、finally:无论如何都执行
- 六、向上抛出异常
- 七、with 语句:优雅管理资源
- 八、自定义异常类
- 九、综合实战
- 十、总结
一、异常是什么?
Python 中语法正确的代码,在运行时也可能发生错误,这种运行期检测到的错误称为异常(Exception)。
🎯 异常处理的目的不是"规避错误",而是当错误发生时提供解决方案,让程序继续执行而不是直接崩溃。
常见异常类型:
| ZeroDivisionError | 除以零 | 10 / 0 |
| NameError | 变量未定义 | print(未定义变量) |
| TypeError | 类型错误 | 1 + 'str' |
| ValueError | 值错误 | int('abc') |
| IndexError | 索引越界 | [][0] |
| KeyError | 字典键不存在 | {}['key'] |
| FileNotFoundError | 文件不存在 | open('不存在.txt') |
二、try/except 基础捕获
使用 try/except 语句捕获异常并处理:
try:
result = 3 / 0 # 可能发生异常的代码
print('没有发生异常') # 这行不会执行
except:
print('发生了异常') # 捕获到异常后执行
print('End') # 程序继续运行
执行逻辑:
没有发生异常 → 忽略 except 中的代码,继续向下执行
发生异常 → 忽略 try 中剩余代码,执行 except 中的代码
三、捕获指定类型异常
实际开发中,我们通常需要针对不同异常做不同处理,并获取异常描述信息:
try:
# result = 3 / 0 # ZeroDivisionError
# print(1 + 'str') # TypeError
# print(res_) # NameError
pass
except ZeroDivisionError as e:
print(f'除零错误: {e}')
except NameError as e:
print(f'名称错误: {e}')
except TypeError as e:
print(f'类型错误: {e}')
except RuntimeError as e:
print(f'运行时错误: {e}')
except:
print('Unexpected error') # 兜底:捕获所有未匹配的异常
print('End')
异常匹配规则:
1. 没有异常 → 忽略所有 except,继续执行
2. 发生异常 → 根据异常类型匹配对应的 except 并执行
3. 异常类型无法匹配任何 except → 异常向外传递(程序崩溃)
💡 多个异常可以合并处理:
except (TypeError, ValueError) as e:
print(e)
四、else:没有异常时执行
else 块在 try 中没有发生异常时执行:
try:
result = 10 / 1
except ZeroDivisionError as e:
print(e)
else:
print(result) # 10.0(没有异常时执行)
为什么要用 else 而不是把代码放在 try 里?
虽然执行效果一样,但放在 else 中更利于代码维护和理解——try 中只放可能出错的代码,else 中放正常逻辑。
五、finally:无论如何都执行
finally 块无论是否发生异常都会执行,常用于资源释放、关闭连接等清理操作:
try:
res = 10 / 0
except NameError as e:
print(e)
except ZeroDivisionError as e:
print(e)
else:
print(res)
finally:
print('Finally 正常结束') # 无论如何都会执行
print('End')
finally vs try/except 外部代码
| try 正常结束 | ✅ 执行 | ✅ 执行 |
| try 异常且 except 捕获 | ✅ 执行 | ✅ 执行 |
| try 异常但 except 未捕获 | ✅ 执行 | ❌ 不执行(异常向外传递) |
🎯 结论: finally 比外部代码更可靠。当 try 中发生未被捕获的异常时,finally 依然会执行,而外部代码不会。
六、向上抛出异常
6.1 raise:主动抛出异常
当你需要在代码中主动触发异常时,使用 raise:
def add(a, b):
if isinstance(a, int) and isinstance(b, int):
return a + b
else:
raise TypeError('参数必须是整数类型')
try:
print(add(1, '2'))
except TypeError as e:
print(e) # 参数必须是整数类型
6.2 assert:断言
assert 用于调试程序,当表达式为 False 时触发异常:
def add(a, b):
assert isinstance(a, int) and isinstance(b, int), '参数错误'
return a + b
try:
print(add(1.0, 2))
except AssertionError as e:
print(e) # 参数错误
| raise | raise 异常类型("描述") | 主动抛出异常,用于业务逻辑 |
| assert | assert 表达式, "描述" | 调试断言,条件为 False 时触发 |
七、with 语句:优雅管理资源
with 语句可以自动管理资源的获取与释放,等效于 try/finally,但更简洁。
工作原理
with 要求对象实现 __enter__ 和 __exit__ 方法:
1. 进入 with → 调用 __enter__() 获取资源
2. 执行代码块
3. 离开 with → 自动调用 __exit__() 释放资源(无论是否异常)
文件操作对比
不用 with(繁琐):
try:
file = open('test.txt', 'w')
try:
file.write('hello world')
finally:
file.close()
finally:
print('文件是否关闭', file.closed)
用 with(推荐):
try:
with open('test.txt', 'w') as f:
f.write('hello world')
finally:
print('文件是否关闭', f.closed) # True(自动关闭)
💡 with 等效于 try/finally,无论代码是否正常运行,都会执行 __exit__ 释放资源。
八、自定义异常类
Python 允许你继承 Exception 类来创建自定义异常,使异常语义更清晰:
class InvalidAgeError(Exception):
"""无效年龄异常"""
def __init__(self, age):
self.age = age
def __str__(self):
return f"无效年龄: {self.age},年龄不能为负数"
class UnrealisticAgeError(Exception):
"""不现实的年龄异常"""
def __init__(self, age):
self.age = age
def __str__(self):
return f"不现实的年龄: {self.age},年龄不能超过120"
def check_age(age):
if age < 0:
raise InvalidAgeError(age)
elif age > 120:
raise UnrealisticAgeError(age)
return age
try:
age = check_age(int(input('请输入年龄: ')))
print(f'年龄: {age}')
except UnrealisticAgeError as e:
print(e)
except InvalidAgeError as e:
print(e)
自定义异常的优势:
- 语义更明确:InvalidAgeError 比 ValueError 更直观
- 可以携带自定义属性(如 self.age)
- 便于分层处理不同业务异常
九、综合实战
场景1:安全的类型转换 + 文件写入
将用户输入转换为整数,失败时把错误信息写入日志文件:
P_s = "123abc"
try:
P_i = int(P_s)
except ValueError as e:
with open('test.txt', 'w+') as f:
f.write(str(e)) # 写入错误信息:invalid literal for int()…
else:
print(P_i)
finally:
print('文件是否关闭', f.closed) # True
场景2:自定义异常验证用户输入
class InvalidAgeError(Exception):
def __init__(self, age):
self.age = age
def __str__(self):
return f"无效年龄: {self.age},年龄不能为负数"
class UnrealisticAgeError(Exception):
def __init__(self, age):
self.age = age
def __str__(self):
return f"不现实的年龄: {self.age},年龄不能超过120"
def check_age(age):
if age < 0:
raise InvalidAgeError(age)
elif age > 120:
raise UnrealisticAgeError(age)
return age
try:
age = check_age(200)
print(f'年龄: {age}')
except UnrealisticAgeError as e:
print(e) # 不现实的年龄: 200,年龄不能超过120
except InvalidAgeError as e:
print(e)
十、总结
| try | 包裹可能出错的代码 | — |
| except | 捕获并处理异常 | 发生匹配的异常时 |
| else | 正常逻辑 | try 中没有异常时 |
| finally | 清理工作 | 无论如何都执行 |
| raise | 主动抛出异常 | 业务需要时 |
| assert | 调试断言 | 表达式为 False 时 |
| with | 自动资源管理 | 等效于 try/finally |
异常处理最佳实践:
🎯 一句话总结: try 管出错,except 管处理,else 管正常,finally 管收尾。掌握这四个关键字,Python 异常处理就通关了。
如果这篇文章对你有帮助,欢迎点赞 👍 收藏 ⭐ 评论 💬 支持一下!



