Skip to content

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 记录错误
# - 成功则添加到列表

下一步

下一节学习 调试技巧

继续!

基于 MIT 许可证发布。内容版权归作者所有。