Python异常规避案例如何预防报错

wen python案例 27

本文目录导读:

Python异常规避案例如何预防报错

  1. 文件操作异常
  2. 字典键访问异常
  3. 列表/索引访问异常
  4. 除法运算异常
  5. 类型转换异常
  6. 网络请求异常
  7. 属性访问异常
  8. 数据库操作异常

在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 []
  1. 优先使用LBYL:在可能出错的地方提前检查
  2. 使用类型注解:减少类型相关的错误
  3. 提供默认值:使用 get(), setdefault(), getattr() 等方法
  4. 使用守卫语句(Guard Clause):尽早返回或处理异常情况
  5. 验证输入:在处理外部数据前进行验证
# 综合示例
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程序中的异常,提高代码的健壮性和可维护性。

抱歉,评论功能暂时关闭!