一、异常处理基础
1. 什么是异常?
异常是程序运行中出现的错误,例如:
- 除以零(ZeroDivisionError)
- 文件不存在(FileNotFoundError)
- 网络连接失败(ConnectionError)
如果不处理异常,程序会直接崩溃!
2. 异常处理的核心语法
使用try-except语句捕获并处理异常:
try:
# 可能出错的代码
result = 10 / 0 # 触发 ZeroDivisionError
except ZeroDivisionError:
print("除数不能为零!") # 异常处理逻辑
二、常见异常类型
Python内置了丰富的异常类型,以下是常见场景:
异常类型 | 触发场景 | 示例 |
ZeroDivisionError | 除数为零 | 10 / 0 |
FileNotFoundError | 文件不存在 | open("nonexistent.txt") |
ValueError | 无效的值(如转换失败) | int("abc") |
KeyError | 字典中不存在的键 | d = {}; d["missing_key"] |
IndexError | 列表/元组索引越界 | lst = [1,2]; lst[3] |
AttributeError | 对象没有该属性 | "str".non_existent_method() |
TypeError | 类型不匹配 | 10 + "hello" |
三、异常处理的进阶用法
1. 捕获多个异常
try:
# 可能出错的代码
f = open("file.txt")
result = 10 / 0
except FileNotFoundError:
print("文件不存在!")
except ZeroDivisionError:
print("除数不能为零!")
2. 捕获所有异常
try:
# 可能出错的代码
except Exception as e:
print(f"发生未知错误:{e}") # 打印异常详情
3.finally块:无论是否异常都会执行
try:
f = open("file.txt")
# 操作文件
except FileNotFoundError:
print("文件不存在!")
finally:
f.close() # 确保文件关闭(即使发生异常)
4.else块:无异常时执行
try:
result = 10 / 2
except ZeroDivisionError:
print("除数不能为零!")
else:
print(f"计算结果:{result}") # 仅在无异常时执行
四、自定义异常
通过继承Exception类创建自定义异常:
class InvalidInputError(Exception):
"""自定义异常:输入无效"""
try:
value = int(input("请输入数字:"))
if value < 0:
raise InvalidInputError("数字不能为负!") # 主动抛出异常
except InvalidInputError as e:
print(f"错误:{e}")
五、实战案例:文件操作与异常处理
需求:读取文件内容,若文件不存在则创建,若内容非数字则报错。
try:
with open("data.txt", "r") as f:
content = f.read()
number = int(content)
print(f"数字:{number}")
except FileNotFoundError:
print("文件不存在,正在创建...")
with open("data.txt", "w") as f:
f.write("42")
except ValueError:
print("文件内容不是有效的数字!")
六、最佳实践
- 具体优于通用
避免使用裸露的except,尽量捕获特定异常:
# 不推荐
try:
...
except:
...
# 推荐
try:
...
except FileNotFoundError:
...
- 记录异常信息
使用logging模块记录异常,便于调试:
import logging
try:
...
except Exception as e:
logging.error(f"错误发生:{e}", exc_info=True) # 输出完整堆栈跟踪
- 使用上下文管理器(with语句)
自动管理资源(如文件、网络连接):
with open("file.txt") as f:
content = f.read() # 自动关闭文件
- 避免隐藏错误
确保异常处理不破坏程序逻辑:
# 错误:吞掉异常
try:
...
except:
pass
# 正确:处理异常或重新抛出
try:
...
except CriticalError:
raise # 重新抛出异常
七、本周练习与答案
练习1:用户输入验证
要求用户输入年龄(整数),若输入非数字或负数则报错。
答案:
while True:
try:
age = int(input("请输入年龄:"))
if age < 0:
raise ValueError("年龄不能为负!")
break
except ValueError as e:
print(f"错误:{e}")
练习2:网络请求重试
模拟网络请求失败时自动重试3次。
答案:
import requests
from time import sleep
url = " https://api.example.com/data "
retries = 3
for attempt in range(retries):
try:
response = requests.get(url)
response.raise_for_status() # 触发HTTPError异常(如404)
print("请求成功!")
break
except requests.exceptions.RequestException as e:
print(f"请求失败(尝试{attempt+1}/{retries}):{e}")
sleep(1) # 等待1秒后重试
else:
print("所有尝试均失败!")
练习3:自定义上下文管理器
实现一个自动计时的上下文管理器。
答案:
import time
from contextlib import contextmanager
@contextmanager
def timer():
start = time.time()
try:
yield # 执行with块内的代码
finally:
end = time.time()
print(f"耗时:{end - start:.2f}秒")
# 使用示例
with timer():
time.sleep(1) # 模拟耗时操作
八、总结与下一步
- 核心收获:
- 异常处理的核心语法:try-except-else-finally。
- 常见异常类型及自定义异常。
- 如何通过异常增强程序健壮性。
