一、什么是异常(Exception)?
异常是指程序运行过程中出现的错误情况。比如:
- 打开一个不存在的文件
- 0作为除数
- 列表索引越界
- 类型转换失败
二、基本结构:try...except
try:# 可能出错的代码
except 错误类型:# 出错时执行的代码
示例:
try:x = 10 / 0 # 除零错误
except ZeroDivisionError:print("不能除以0")
输出:
不能除以0
三、完整结构详解
try:# 尝试执行的代码块
except 错误类型1:# 捕获错误类型1后的处理
except 错误类型2:# 捕获错误类型2后的处理
else:# 没有异常时执行
finally:# 无论是否有异常都执行(如关闭文件/资源)
示例:
try:num = int(input("请输入一个整数:"))result = 10 / num
except ValueError:print("请输入有效的整数")
except ZeroDivisionError:print("不能输入0")
else:print("结果是:",result)
finally:print("程序结束")
四、常见异常类型及用途
异常类型 | 触发场景 |
ZeroDivisionError | 除以零 |
ValueError | 类型转换失败,如 int("abc") |
IndexError | 索引超出列表范围 |
KeyError | 字典中访问不存在的键 |
FileNotFoundError | 打开一个不存在的文件 |
TypeError | 操作类型不兼容 |
五、常见实用技巧和场景
1.捕获多个异常
try:a = int("abc")b = 10 /0
except (ValueError,ZeroDivisionError) as e:print("出错啦",e)
2.不确定错误类型,先写Exception
try:# 复杂逻辑do_something()
except Exception as e:print("出现未知错误",e)
注意:不要滥用Exception,否则可能掩盖真正的bug
3.使用finally清理资源
try:file = open("data.txt","r")content = file.read()
except FileNotFound:print("文件未找到")
finally:file.close()print("文件关闭")
4.自定义函数内使用try-except
def safe_divide(x,y):try:return x/yecxept ZeroDivisionError:return "不能除以0"print(safe_divide(10,0)) #输出:不能除以0
六、自定义异常类(Custom Exceptions)
有时候内置异常不能准确表达业务逻辑,此时可以自定义异常类
语法:
class 自定义异常名(Exception):pass
示例:
# 定义一个自定义异常类,继承自内置的Exception类
class PasswordTooShortError(Exception):"""密码长度太短的异常"""pass# 定义一个检查密码的函数
def check_password(pwd):#如果密码长度小于6,就主动抛出自定义异常if len(pwd)<6:raise PasswordTooShortError("密码长度不能少于6位")# 使用try-except捕获自定义异常
try:check_password("abc")
except PasswordTooShortError as e:#捕获到自定义异常后,打印错误信息print("发生错误:",e)
七、使用raise主动抛出异常
raise可以手动触发异常,让函数调用者知道出错了
基本用法:
raise 异常类型("错误信息")
示例:
# 定义一个除法函数,带参数检查
def divide(x,y):# 如果除数是0,就主动抛出除零异常if y == 0:rasie ZeroDivisionError("除数不能为0")# 否则返回除法结果return x/y# 使用try-except 捕获异常
try:result = divide(10,0)
except ZeroDivisionError as e: #重命名异常,以便于后续再输出错误信息print("错误",e)
八、异常链(raise...from...)
在某些场景中,一个异常是由另一个异常引起的,为了因果链,可以使用:
raise 新异常 from 原始异常
示例:
# 定义一个读取配置文件的函数
def read_config(path):try:# 试图打开并读取文件内容with open(path) as f:return f.read()except FileNotFoundError as e:# 如果文件找不到,抛出新的RuntimeError,并保留原始异常信息raise RuntimeError("配置文件读取失败") from e# 使用try-except捕获RuntimeError
try:read_config("no_such_file.cfg") #尝试读取一个不存在的文件
except RuntimeError as e:#打印新的异常信息print("RuntimeError:",e)#打印原始异常的详细原因(通过异常链追踪)print("原始原因:",e.__casuse__)
九、高级技巧总结表
技巧 | 说明 | 示例代码 |
自定义异常类 | 用于表达特定业务逻辑错误 | class MyError(Exception):.. |
raise抛出异常 | 控制程序流,校验参数 | raise ValueError("不合法") |
raise from原始异常 | 保留原始异常上下文 | raise NewError from old_error |
异常嵌套处理 | 不同层次处理不同错误 | 外层用broad except,内层细分异常处理 |
异常日志记录 | 结合logging模块记录错误信息 | logging.exception(e) |