在编程过程中,程序难免会遇到各种错误和意外情况。Python 提供了强大的异常处理机制,帮助开发者优雅地应对这些问题,避免程序因一个错误而直接崩溃。本文将系统介绍 Python 中常见的异常类型、异常处理语法以及最佳实践。
一、什么是异常(Exception)?
异常是指程序在运行过程中发生的错误事件,它会中断正常的执行流程。例如:除以零、访问不存在的文件、调用无效的方法等。
Python 使用“抛出异常”(raise exception)的方式来通知错误,并允许我们通过捕获异常(catch exception)来处理这些错误。
✅ 正确处理异常可以让程序更健壮、用户体验更好。
二、常见内置异常类型
Python 内置了多种异常类,所有异常都继承自BaseException。以下是开发中最常遇到的一些异常类型:
| 异常类型 | 触发场景 | 示例 |
|---|---|---|
SyntaxError | 语法错误(代码写错) | if True print("hello") |
IndentationError | 缩进错误 | 错误的空格/Tab使用 |
NameError | 变量未定义 | print(x)而x未声明 |
TypeError | 类型不匹配 | '2' + 2(字符串加整数) |
ValueError | 值不合适 | int("abc") |
IndexError | 索引越界 | lst[10]而列表只有3个元素 |
KeyError | 字典键不存在 | dct['missing_key'] |
AttributeError | 对象没有该属性 | obj.nonexistent_method() |
FileNotFoundError | 文件不存在 | open('missing.txt') |
IOError/OSError | 输入输出错误(如权限不足) | 读写文件失败 |
ZeroDivisionError | 除以零 | 5 / 0 |
ImportError | 导入模块失败 | import nonexistent_module |
ModuleNotFoundError | 模块未找到(ImportError 子类) | 导入不存在的包 |
KeyboardInterrupt | 用户按下 Ctrl+C 终止程序 | 手动中断运行 |
📌提示:这些异常都是类,可以被捕捉和处理。
三、异常处理的基本语法:try-except
Python 使用try...except结构来捕获并处理异常。
基本结构:
try:
# 尝试执行可能出错的代码
result = 10 / 0
except ZeroDivisionError:
# 如果发生指定异常,则执行这里的代码
print("不能除以零!")
捕获多个异常
方法1:分别处理不同异常
try:
num = int(input("请输入一个数字:"))
result = 10 / num
print(f"结果是:{result}")
except ValueError:
print("输入的不是有效数字!")
except ZeroDivisionError:
print("不能除以零!")
方法2:用一个 except 处理多个异常
except (ValueError, ZeroDivisionError) as e:
print(f"发生了错误:{e}")
四、完整的异常处理结构:try-except-else-finally
Python 支持更复杂的异常控制结构:
try:
file = open("data.txt", "r")
content = file.read()
number = int(content.strip())
except FileNotFoundError:
print("文件未找到。")
except ValueError:
print("文件内容不是一个有效的数字。")
else:
# try 成功执行后才运行(无异常)
print(f"读取到的数字是:{number}")
finally:
# 无论是否出错都会执行(通常用于清理资源)
print("清理工作...")
各部分作用说明:
| 块 | 是否必需 | 功能 |
|---|---|---|
try | 是 | 包含可能出错的代码 |
except | 是(至少一个) | 捕获并处理异常 |
else | 否 | 无异常时执行 |
finally | 否 | 总是执行(适合关闭文件、释放资源等) |
五、抛出异常:raise关键字
我们可以主动抛出异常,用于验证条件或传递错误信息。
示例1:手动抛出异常
age = -5
if age < 0:
raise ValueError("年龄不能为负数!")
示例2:自定义异常信息
raise TypeError("期望字符串类型,但得到了整数")
示例3:重新抛出异常(用于日志记录后继续传播)
try:
risky_operation()
except Exception as e:
print(f"记录错误:{e}")
raise # 重新抛出原异常
六、自定义异常类
当内置异常无法满足需求时,我们可以创建自己的异常类型。
创建自定义异常
class InvalidAgeError(Exception):
"""表示年龄无效的自定义异常"""
def __init__(self, age, message="年龄不在合法范围内"):
self.age = age
self.message = message
super().__init__(self.message)
# 使用自定义异常
def set_age(age):
if not (0 <= age <= 150):
raise InvalidAgeError(age)
print(f"设置年龄为:{age}")
# 调用测试
try:
set_age(200)
except InvalidAgeError as e:
print(f"错误:{e}(输入的年龄是 {e.age})")
输出:
错误:年龄不在合法范围内(输入的年龄是 200)✅ 自定义异常有助于提高代码可读性和维护性。
七、实际应用示例:安全读取配置文件
import json
def load_config(file_path):
try:
with open(file_path, 'r', encoding='utf-8') as f:
config = json.load(f)
except FileNotFoundError:
print(f"警告:配置文件 {file_path} 不存在,使用默认配置。")
return {"host": "localhost", "port": 8080}
except json.JSONDecodeError as e:
print(f"配置文件格式错误:{e}")
return {}
except PermissionError:
print("没有权限读取配置文件。")
return None
else:
print("配置加载成功。")
return config
finally:
print("配置加载过程结束。")
# 使用
config = load_config("config.json")
八、异常处理的最佳实践
不要滥用
except:或except Exception:# ❌ 危险!会隐藏所有错误
try:
something()
except:
pass
尽量具体地捕获异常
# ✅ 推荐
except ValueError as e:
handle_value_error(e)
记录异常信息便于调试
import logging
try:
...
except Exception as e:
logging.error(f"发生异常:{e}", exc_info=True)
避免空的
except块至少打印或记录错误信息。使用
with替代手动资源管理如文件操作中使用with open(),自动处理关闭。不要忽略 KeyboardInterrupt 和 SystemExit它们是用户中断信号,不应被普通
except Exception捕获。
九、总结
| 要点 | 说明 |
|---|---|
| 🎯 目标 | 让程序在出错时不崩溃,提供友好反馈 |
| 🔧 核心语法 | try,except,else,finally,raise |
| 📚 常见异常 | ValueError,TypeError,FileNotFoundError等 |
| 💡 最佳做法 | 精确捕获、合理处理、适当抛出、日志记录 |
| 🛠️ 高级技巧 | 自定义异常、链式异常、上下文管理器配合使用 |
🎯小练习建议:
编写一个函数safe_divide(a, b),实现两个数的安全除法:
- 若
b == 0,捕获ZeroDivisionError - 若参数不是数字,捕获
TypeError - 成功则返回结果,失败则返回
None并提示错误信息
def safe_divide(a, b):
try:
return a / b
except ZeroDivisionError:
print("错误:除数不能为零。")
return None
except TypeError:
print("错误:请输入数字。")
return None
print(safe_divide(10, 2)) # 5.0
print(safe_divide(10, 0)) # 错误提示
print(safe_divide("a", 2)) # 错误提示
掌握异常处理是成为合格 Python 开发者的重要一步。善用异常机制,让你的程序更加稳定、可靠、易于维护!