本文目录导读:

在Python中,异常规避(Exception Avoidance)的核心思想是“先检查,后操作”(Look Before You Leap, LBYL),而不是“事后处理”**(Easier to Ask for Forgiveness than Permission, EAFP),以下是一些常见的异常规避案例及其预防方法:
文件操作异常
❌ 容易报错的做法
# 直接打开文件,如果不存在会报错
file = open('data.txt', 'r')
content = file.read()
✅ 异常规避方案
import os
# 方法1:检查文件是否存在
if os.path.exists('data.txt') and os.path.isfile('data.txt'):
with open('data.txt', 'r') as file:
content = file.read()
else:
print("文件不存在或不是文件")
# 方法2:使用 pathlib(推荐)
from pathlib import Path
file_path = Path('data.txt')
if file_path.is_file():
content = file_path.read_text()
else:
print("文件不存在")
字典键访问异常
❌ 容易报错的做法
user = {'name': 'Tom', 'age': 25}
# 如果键不存在会报 KeyError
email = user['email']
✅ 异常规避方案
user = {'name': 'Tom', 'age': 25}
# 方法1:使用 get() 方法
email = user.get('email', 'default@email.com') # 返回默认值
# 方法2:使用 setdefault() 方法
email = user.setdefault('email', 'default@email.com') # 不存在则设置默认值
# 方法3:使用 defaultdict
from collections import defaultdict
user_dict = defaultdict(lambda: 'default@email.com')
user_dict.update(user)
print(user_dict['email']) # 不会报错
列表/索引访问异常
❌ 容易报错的做法
numbers = [1, 2, 3] # 如果索引超出范围会报 IndexError value = numbers[5]
✅ 异常规避方案
numbers = [1, 2, 3]
# 方法1:检查索引范围
def safe_get(lst, index, default=None):
if 0 <= index < len(lst):
return lst[index]
return default
value = safe_get(numbers, 5, 'not found')
# 方法2:使用切片(不会报错)
value = numbers[5:6] # 返回空列表 []
value = numbers[5:6] or 'not found'
除法运算异常
❌ 容易报错的做法
# 除数为零会报 ZeroDivisionError result = 10 / 0
✅ 异常规避方案
# 方法1:检查除数
def safe_divide(a, b):
if b != 0:
return a / b
return float('inf') # 或返回其他默认值
# 方法2:使用 Decimal 类型
from decimal import Decimal, DivisionByZero
try:
result = Decimal(10) / Decimal(0)
except DivisionByZero:
result = Decimal('Infinity')
类型转换异常
❌ 容易报错的做法
# 字符串无法转换为整数会报 ValueError
number = int("abc")
✅ 异常规避方案
# 方法1:使用字符串方法检查
def safe_int(value, default=0):
if isinstance(value, str) and value.strip().isdigit():
return int(value)
if isinstance(value, (int, float)):
return int(value)
return default
# 方法2:使用正则表达式
import re
def safe_int_regex(value, default=0):
if re.match(r'^[+-]?\d+$', str(value)):
return int(value)
return default
网络请求异常
❌ 容易报错的做法
import requests
# 网络异常或服务器错误会报异常
response = requests.get('https://example.com')
✅ 异常规避方案
import requests
from requests.exceptions import RequestException
def safe_request(url, timeout=5):
# 先检查 URL 格式
if not url.startswith(('http://', 'https://')):
print("无效的URL格式")
return None
try:
response = requests.get(url, timeout=timeout)
response.raise_for_status() # 检查 HTTP 状态码
return response.json()
except RequestException as e:
print(f"请求失败: {e}")
return None
except ValueError as e:
print(f"JSON解析失败: {e}")
return None
属性访问异常
❌ 容易报错的做法
class User:
def __init__(self, name):
self.name = name
user = User('Tom')
# 如果属性不存在会报 AttributeError
email = user.email
✅ 异常规避方案
# 方法1:使用 hasattr() 检查
user = User('Tom')
if hasattr(user, 'email'):
email = user.email
else:
email = 'default@email.com'
# 方法2:使用 getattr() 方法
email = getattr(user, 'email', 'default@email.com')
# 方法3:使用 __getattribute__ 自定义
class SafeUser:
def __init__(self, name):
self.name = name
self._defaults = {'email': 'default@email.com'}
def __getattribute__(self, name):
try:
return super().__getattribute__(name)
except AttributeError:
defaults = super().__getattribute__('_defaults')
return defaults.get(name, f"属性'{name}'不存在")
数据库操作异常
❌ 容易报错的做法
import sqlite3
conn = sqlite3.connect('database.db')
# 如果表不存在会报错
cursor = conn.execute("SELECT * FROM users")
✅ 异常规避方案
import sqlite3
from sqlite3 import OperationalError
def safe_query(database, query, params=None):
try:
conn = sqlite3.connect(database)
if params:
cursor = conn.execute(query, params)
else:
cursor = conn.execute(query)
# 获取字段名
columns = [description[0] for description in cursor.description]
result = [dict(zip(columns, row)) for row in cursor.fetchall()]
conn.close()
return result
except OperationalError as e:
print(f"数据库操作错误: {e}")
return []
except Exception as e:
print(f"未知错误: {e}")
return []
- 优先使用LBYL:在可能出错的地方提前检查
- 使用类型注解:减少类型相关的错误
- 提供默认值:使用
get(),setdefault(),getattr()等方法 - 使用守卫语句(Guard Clause):尽早返回或处理异常情况
- 验证输入:在处理外部数据前进行验证
# 综合示例
def process_user_data(data: dict) -> dict:
"""安全的用户数据处理函数"""
# 守卫语句:检查数据类型
if not isinstance(data, dict):
return {'error': '无效的数据格式'}
# 使用get方法获取默认值
return {
'name': data.get('name', 'Unknown'),
'age': int(data.get('age', 0)) if str(data.get('age', '')).isdigit() else 0,
'email': data.get('email', 'no_email@example.com'),
'status': 'active' if data.get('status') == 1 else 'inactive'
}
通过这种方式,你可以有效减少Python程序中的异常,提高代码的健壮性和可维护性。