try-except 异常处理
优雅地处理错误
基本语法
python
try:
# 可能出错的代码
risky_operation()
except ExceptionType:
# 出错时的处理
handle_error()基本用法
示例 1:捕获特定异常
python
try:
age = int(input("请输入年龄: "))
print(f"你的年龄是 {age}")
except ValueError:
print(" 请输入有效的数字")示例 2:捕获多种异常
python
try:
income = int(input("收入: "))
tax = income / 0.25
except ValueError:
print(" 收入必须是数字")
except ZeroDivisionError:
print(" 除数不能为零")示例 3:捕获所有异常
python
try:
# 危险操作
result = risky_function()
except Exception as e:
print(f" 发生错误: {e}")完整语法
try-except-else-finally
python
try:
# 尝试执行的代码
result = 10 / 2
except ZeroDivisionError:
# 出错时执行
print(" 除以零")
else:
# 没出错时执行
print(f" 结果: {result}")
finally:
# 无论如何都执行(清理资源)
print("计算完成")实战案例
案例 1:安全的数据读取
python
import pandas as pd
from pathlib import Path
def load_survey_data(filename):
"""安全地加载问卷数据"""
try:
if not Path(filename).exists():
raise FileNotFoundError(f"文件不存在: {filename}")
df = pd.read_csv(filename)
# 验证必要列
required_cols = ['id', 'age', 'income']
missing_cols = set(required_cols) - set(df.columns)
if missing_cols:
raise ValueError(f"缺少列: {missing_cols}")
return df
except FileNotFoundError as e:
print(f" 文件错误: {e}")
return None
except pd.errors.EmptyDataError:
print(" 文件为空")
return None
except Exception as e:
print(f" 未知错误: {e}")
return None
# 使用
df = load_survey_data('survey.csv')
if df is not None:
print(f" 成功加载 {len(df)} 行数据")案例 2:批量数据处理
python
# 问卷数据(可能有错误)
responses = [
{'id': 1, 'age': '25', 'income': '50000'},
{'id': 2, 'age': 'N/A', 'income': '75000'},
{'id': 3, 'age': '35', 'income': 'unknown'},
{'id': 4, 'age': '40', 'income': '85000'}
]
valid_data = []
errors = []
for resp in responses:
try:
# 尝试转换
clean_resp = {
'id': resp['id'],
'age': int(resp['age']),
'income': float(resp['income'])
}
valid_data.append(clean_resp)
except (ValueError, KeyError) as e:
errors.append({
'id': resp.get('id', 'unknown'),
'error': str(e)
})
print(f" 有效数据: {len(valid_data)} 条")
print(f" 错误数据: {len(errors)} 条")
for error in errors:
print(f" ID {error['id']}: {error['error']}")案例 3:API 请求重试
python
import requests
import time
def fetch_data(url, max_retries=3):
"""带重试的 API 请求"""
for attempt in range(max_retries):
try:
response = requests.get(url, timeout=5)
response.raise_for_status() # 检查 HTTP 错误
return response.json()
except requests.exceptions.Timeout:
print(f"⏱️ 超时,重试 {attempt + 1}/{max_retries}")
time.sleep(2 ** attempt) # 指数退避
except requests.exceptions.HTTPError as e:
print(f" HTTP 错误: {e}")
return None
except requests.exceptions.RequestException as e:
print(f" 请求错误: {e}")
return None
print(f" 达到最大重试次数")
return None最佳实践
1. 捕获具体的异常
python
# 太宽泛
try:
result = risky_operation()
except:
print("出错了")
# 具体明确
try:
result = risky_operation()
except ValueError:
print("值错误")
except FileNotFoundError:
print("文件不存在")2. 使用 else 子句
python
try:
df = pd.read_csv('data.csv')
except FileNotFoundError:
print(" 文件不存在")
else:
# 只在成功时执行
print(f" 加载 {len(df)} 行")
df.to_stata('output.dta')3. finally 清理资源
python
file = None
try:
file = open('data.txt', 'r')
content = file.read()
except FileNotFoundError:
print(" 文件不存在")
finally:
# 确保文件被关闭
if file:
file.close()
# 更好的方式:使用 with
with open('data.txt', 'r') as file:
content = file.read() # 自动关闭4. 记录错误日志
python
import logging
logging.basicConfig(filename='app.log', level=logging.ERROR)
try:
result = risky_operation()
except Exception as e:
logging.error(f"错误: {e}", exc_info=True)
print(" 发生错误,详见日志")自定义异常
python
class InvalidAgeError(Exception):
"""年龄无效异常"""
pass
def validate_respondent(age, income):
"""验证受访者数据"""
if age < 18 or age > 100:
raise InvalidAgeError(f"年龄无效: {age}")
if income < 0:
raise ValueError(f"收入不能为负数: {income}")
# 使用
try:
validate_respondent(age=150, income=50000)
except InvalidAgeError as e:
print(f" {e}")
except ValueError as e:
print(f" {e}")何时使用 try-except?
适合的场景
- 文件操作(文件可能不存在)
- 网络请求(可能超时)
- 用户输入(可能无效)
- 数据转换(可能失败)
不适合的场景
python
# 不要用异常处理代替正常逻辑
try:
value = dict['key']
except KeyError:
value = None
# 使用条件判断
value = dict.get('key', None)练习题
python
# 练习 1:安全的均值计算
def safe_mean(data):
"""计算均值,处理空列表和非数字"""
try:
# 你的代码
pass
except:
return None
# 练习 2:文件批处理
# 读取文件夹中所有 CSV
# 对每个文件:
# - try 读取
# - except 记录错误
# - 成功则添加到列表下一步
下一节学习 调试技巧。
继续!