Python 异常捕获与处理:从基础语法到工程化实践的万字深度指南

核心目标:系统掌握 Python 异常的底层原理、语法细节、高级特性生产级处理方案,避免 “吞异常”“乱捕获” 等致命错误


引言:一个因异常处理缺失导致的生产事故

2023 年,某电商公司的 Python 商品推荐接口因 ** 未捕获的KeyError** 导致服务崩溃:

  • 接口逻辑中直接访问字典的item['discount']字段,但部分商品数据缺失该字段;
  • 未加异常捕获,异常直接抛出导致 UWSGI worker 重启,服务可用性从 99.99% 降至 95%;
  • 修复前 30 分钟内,损失约 10 万次有效请求,影响 GMV 约 20 万元。

这个案例充分说明:异常处理不是 “可选的代码优化”,而是系统稳定性的 “生命线”。Python 作为一门动态语言,异常是其 “错误处理机制” 的核心,掌握正确的异常处理方式,是从 “能写 Python” 到 “能写可靠 Python” 的关键。


一、Python 异常的底层原理与体系结构

1.1 什么是异常?

异常是指程序运行过程中出现的非预期情况,比如:

  • 访问不存在的列表索引(IndexError);
  • 除数为 0(ZeroDivisionError);
  • 打开不存在的文件(FileNotFoundError)。

Python 的异常处理采用 **“终止式” 模型 **:当异常发生时,程序会立即停止当前执行路径,跳转到最近的异常处理块(except),若未找到则终止程序并打印栈跟踪信息。

1.2 异常体系的核心结构

Python 的所有异常都继承自 **BaseException** 基类,其核心体系结构如下:

BaseException  # 所有异常的根类
├── SystemExit  # sys.exit()触发,用于程序退出
├── KeyboardInterrupt  # Ctrl+C触发,用户中断
├── GeneratorExit  # 生成器关闭时触发
└── Exception  # 可捕获的“普通异常”基类
    ├── ArithmeticError  # 算术错误(如ZeroDivisionError)
    ├── AssertionError  # assert语句失败
    ├── AttributeError  # 访问不存在的属性
    ├── EOFError  # 文件读取到结尾
    ├── ImportError  # 导入模块失败
    ├── LookupError  # 索引/键错误(如KeyError、IndexError)
    ├── NameError  # 访问未定义的变量
    ├── OSError  # 操作系统错误(如FileNotFoundError、PermissionError)
    ├── TypeError  # 类型不匹配
    ├── ValueError  # 值错误
    └── 自定义异常  # 继承自Exception的业务异常

关键注意点

  • BaseException包含系统级异常SystemExitKeyboardInterrupt等),不应随意捕获,否则会导致程序无法正常退出或无法响应用户中断;
  • 开发中应仅捕获Exception及其子类,避免捕获系统级异常。

1.3 常用内置异常与示例

异常类型触发场景示例代码
ZeroDivisionError除数为 01 / 0
IndexError访问超出列表 / 元组的索引[1,2,3][5]
KeyError访问字典中不存在的键{"a":1}["b"]
TypeError类型不匹配(如字符串 + 整数)"a" + 1
ValueError值不符合预期(如 int ("abc"))int("abc")
FileNotFoundError打开不存在的文件open("not_exist.txt")
PermissionError文件权限不足open("/root/secret.txt", "w")(普通用户)
TimeoutError操作超时requests.get("http://slow.com", timeout=1)

二、异常捕获的基础语法

2.1 核心语法:try-except

try-except是 Python 异常捕获的最基础结构,用于捕获并处理指定的异常

# 基本用法
try:
    # 可能抛出异常的代码块
    result = 10 / int(input("请输入除数:"))
    print(f"结果:{result}")
except ZeroDivisionError:
    # 处理除数为0的异常
    print("错误:除数不能为0!")
except ValueError:
    # 处理输入非数字的异常
    print("错误:请输入有效的整数!")

运行示例

# 输入0 → 输出:错误:除数不能为0!
# 输入abc → 输出:错误:请输入有效的整数!
# 输入2 → 输出:结果:5.0

2.2 捕获多个异常的三种方式

2.2.1 多个except块(推荐)

优点:可以为不同的异常编写不同的处理逻辑,代码清晰;缺点:无法同时处理多个异常的共性逻辑。

2.2.2 元组捕获多个异常

将多个异常类型放在元组中,可以同时处理:

try:
    result = 10 / int(input("请输入除数:"))
except (ZeroDivisionError, ValueError):
    print("错误:请输入非0的有效整数!")
2.2.3 捕获所有可处理的异常(Exception
try:
    # 复杂业务逻辑
except Exception as e:
    print(f"发生错误:{e}")
    # 可以添加日志记录等处理

风险警告:请勿捕获BaseException,否则会捕获SystemExitKeyboardInterrupt等系统级异常,导致程序无法正常退出。

2.3 资源清理的 “铁律”:finally

finally块用于无论是否发生异常,都必须执行的代码,通常用于资源清理(如关闭文件、释放数据库连接等):

# 文件操作的finally示例
file = None
try:
    file = open("test.txt", "r")
    content = file.read()
    print(f"文件内容:{content}")
except FileNotFoundError:
    print("错误:文件不存在!")
finally:
    # 无论是否有异常,都关闭文件
    if file:
        file.close()
2.3.1 with语句:自动资源管理(替代 finally)

Python 的with语句(上下文管理器)可以自动管理资源,无需手动关闭:

try:
    with open("test.txt", "r") as file:
        content = file.read()
        print(f"文件内容:{content}")
except FileNotFoundError:
    print("错误:文件不存在!")
# 文件会自动关闭,无需finally块

原理with语句调用对象的__enter__()方法获取资源,调用__exit__()方法清理资源,即使__enter__()或块内代码抛出异常,__exit__()也会执行。

2.4 无异常时的逻辑:else

else块用于try块中无异常时执行的代码,与except块互斥:

try:
    result = 10 / 2
except ZeroDivisionError:
    print("除数为0")
else:
    # 只有try块无异常时才执行
    print(f"计算成功,结果:{result}")
finally:
    print("无论是否有异常,都会执行")
# 输出:计算成功,结果:5.0 → 无论是否有异常,都会执行

2.5 重新抛出异常:raise语句

有时候需要捕获异常后重新抛出(如添加日志后再抛出,不吞掉异常):

import traceback

try:
    1 / 0
except ZeroDivisionError as e:
    # 记录异常到日志
    print(f"日志:发生ZeroDivisionError:{traceback.format_exc()}")
    # 重新抛出原始异常,不丢失上下文
    raise

三、高级异常处理特性

3.1 异常上下文与raise...from

Python 3 引入了raise...from语法,用于保留原始异常的上下文信息,解决 “异常被覆盖” 的问题:

3.1.1 反例:异常被覆盖
try:
    1 / 0  # 原始异常:ZeroDivisionError
except ZeroDivisionError:
    raise ValueError("自定义错误")  # 新异常:ValueError,覆盖了原始异常
# 输出只显示ValueError,原始异常信息丢失
3.1.2 正例:保留原始异常上下文
try:
    1 / 0
except ZeroDivisionError as e:
    # 用from保留原始异常上下文
    raise ValueError("自定义错误") from e

运行结果(保留了原始异常的栈跟踪):

Traceback (most recent call last):
  File "test.py", line 2, in <module>
    1 / 0
ZeroDivisionError: division by zero

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "test.py", line 5, in <module>
    raise ValueError("自定义错误") from e
ValueError: 自定义错误
3.1.3 清除异常上下文:from None

若不需要原始异常上下文,可以用from None清除:

try:
    1 / 0
except ZeroDivisionError:
    raise ValueError("自定义错误") from None
# 输出只显示ValueError,无原始异常信息

3.2 异常的详细信息:traceback模块

生产环境中,仅打印str(e)无法定位问题,需要完整的栈跟踪信息traceback模块用于获取和打印异常的详细栈信息:

3.2.1 traceback.print_exc():打印栈跟踪
import traceback

try:
    [1,2,3][5]
except IndexError:
    print("发生IndexError:")
    traceback.print_exc()  # 打印完整的栈跟踪

运行结果

发生IndexError:
Traceback (most recent call last):
  File "test.py", line 4, in <module>
    [1,2,3][5]
IndexError: list index out of range
3.2.2 traceback.format_exc():返回栈跟踪字符串

用于将栈跟踪信息保存到日志中(推荐):

import traceback
import logging

# 配置日志
logging.basicConfig(filename="app.log", level=logging.ERROR, format="%(asctime)s - %(levelname)s - %(message)s")

try:
    1 / 0
except ZeroDivisionError as e:
    # 将异常栈信息写入日志
    logging.error(f"ZeroDivisionError: {traceback.format_exc()}")
    print("系统错误,请联系管理员")

日志内容

2024-05-20 16:30:00,123 - ERROR - ZeroDivisionError: Traceback (most recent call last):
  File "test.py", line 8, in <module>
    1 / 0
ZeroDivisionError: division by zero

3.3 异常的参数与属性

异常对象包含以下常用属性:

  • e.args:异常的参数元组;
  • e.__traceback__:异常的栈跟踪对象;
  • e.errno:OS 错误的错误码(仅OSError及其子类);
  • e.strerror:OS 错误的描述信息(仅OSError及其子类)。

示例

try:
    open("not_exist.txt")
except FileNotFoundError as e:
    print(f"args:{e.args}")  # 输出:(2, 'No such file or directory')
    print(f"errno:{e.errno}")  # 输出:2
    print(f"strerror:{e.strerror}")  # 输出:No such file or directory
    print(f"filename:{e.filename}")  # 输出:not_exist.txt(仅FileNotFoundError有此属性)

四、自定义异常:业务化的错误处理

4.1 为什么需要自定义异常?

内置异常无法满足业务场景的细分需求,比如:

  • 支付系统需要 “余额不足异常”“支付超时异常”;
  • 权限系统需要 “未登录异常”“权限不足异常”。

自定义异常可以让错误信息更加明确、可读性更强,同时便于业务逻辑的分层处理。

4.2 自定义异常的基本写法

自定义异常需继承自Exception(不要继承BaseException),可以添加自定义属性和方法:

# 自定义支付异常基类
class PaymentException(Exception):
    def __init__(self, order_id, message):
        super().__init__(message)
        self.order_id = order_id  # 订单号(自定义属性)
    
    # 自定义__str__方法,返回更友好的错误信息
    def __str__(self):
        return f"[订单号:{self.order_id}] {super().__str__()}"

# 具体业务异常:余额不足
class InsufficientBalanceException(PaymentException):
    pass

# 具体业务异常:支付超时
class PaymentTimeoutException(PaymentException):
    pass

# 测试
try:
    raise InsufficientBalanceException("OD2024052001", "用户余额不足")
except PaymentException as e:
    print(f"支付错误:{e}")  # 输出:支付错误:[订单号:OD2024052001] 用户余额不足
    print(f"订单号:{e.order_id}")  # 输出:订单号:OD2024052001

4.3 自定义异常的最佳实践

  1. 继承自Exception:避免继承BaseException
  2. 命名规范:以 “Exception” 结尾(如InsufficientBalanceException);
  3. 添加业务属性:如订单号、用户 ID 等,便于问题定位;
  4. 自定义__str__/__repr__:返回包含业务上下文的错误信息;
  5. 分层设计:先定义基类,再定义具体业务异常,便于统一处理。

五、异步编程中的异常处理

Python 3.8 + 的异步编程(asyncio)已成为企业级开发的标准,异步中的异常处理与同步有所不同。

5.1 异步函数中的基础异常处理

异步函数中的异常可以用同步的try-except语法捕获:

import asyncio

async def divide(a, b):
    if b == 0:
        raise ZeroDivisionError("除数为0")
    return a / b

async def main():
    try:
        result = await divide(10, 0)
        print(f"结果:{result}")
    except ZeroDivisionError as e:
        print(f"异步函数异常:{e}")

# 运行异步主函数
asyncio.run(main())  # 输出:异步函数异常:除数为0

5.2 多个 Task 的异常处理

5.2.1 asyncio.gather():快速失败

asyncio.gather()立即终止所有 Task,当其中一个 Task 抛出异常时:

import asyncio

async def task1():
    await asyncio.sleep(0.5)
    print("Task1完成")
    return 1

async def task2():
    await asyncio.sleep(0.1)
    raise ValueError("Task2失败")

async def main():
    try:
        results = await asyncio.gather(task1(), task2())
        print(f"结果:{results}")
    except Exception as e:
        print(f"异常:{e}")
        # Task1会被取消

asyncio.run(main())  # 输出:异常:Task2失败 → Task1未完成
5.2.2 asyncio.gather(return_exceptions=True):收集所有异常

若要执行所有 Task 并收集异常,可以设置return_exceptions=True

async def main():
    results = await asyncio.gather(task1(), task2(), return_exceptions=True)
    print(f"结果:{results}")  # 输出:结果:[1, ValueError('Task2失败')]

asyncio.run(main())  # Task1和Task2都执行完成
5.2.3 asyncio.wait():手动处理异常

asyncio.wait()返回已完成和已取消的 Task 集合,需要手动处理每个 Task 的异常:

async def main():
    tasks = [task1(), task2()]
    done, pending = await asyncio.wait(tasks, return_when=asyncio.ALL_COMPLETED)
    for task in done:
        try:
            result = task.result()  # 获取Task的结果,若有异常则抛出
            print(f"Task成功:{result}")
        except Exception as e:
            print(f"Task失败:{e}")

asyncio.run(main())
# 输出:Task失败:Task2失败 → Task1成功:1

5.3 async with/async for的异常处理

异步上下文管理器和异步迭代器的异常处理与同步类似:

import aiohttp

async def fetch_url(url):
    try:
        async with aiohttp.ClientSession() as session:
            async with session.get(url, timeout=1) as resp:
                return await resp.text()
    except aiohttp.ClientTimeout:
        print(f"请求{url}超时")
        return None
    except aiohttp.ClientError as e:
        print(f"请求{url}失败:{e}")
        return None

asyncio.run(fetch_url("http://slow.com"))  # 输出:请求http://slow.com超时

六、工程化异常处理最佳实践

6.1 禁止 “吞异常”(except: pass

错误示例

try:
    # 重要的业务逻辑
    update_user_balance(user_id, amount)
except:
    pass  # 吞掉所有异常,导致问题无法定位

风险:无法发现业务逻辑中的错误,导致数据不一致、资金损失等严重问题。解决方案:至少记录异常日志,或重新抛出。

6.2 只捕获必要的异常

错误示例

try:
    # 业务逻辑
except Exception as e:
    print(f"错误:{e}")
    # 模糊处理,无法区分业务异常和系统异常

解决方案先捕获具体的业务异常,再捕获系统异常

try:
    # 业务逻辑
except (InsufficientBalanceException, PaymentTimeoutException) as e:
    # 业务异常:友好提示用户
    return {"code": 400, "message": str(e)}
except (FileNotFoundError, TimeoutError) as e:
    # 系统异常:记录日志,返回通用错误
    logging.error(f"系统错误:{traceback.format_exc()}")
    return {"code": 500, "message": "服务器内部错误"}

6.3 异常处理的粒度要合适

错误示例

try:
    # 100行复杂的业务逻辑
except Exception:
    # 整个块都被捕获,无法定位具体错误位置

解决方案将异常处理的粒度缩小到最小单元,仅捕获可能抛出异常的代码段:

# 业务逻辑1:不可能抛出异常
user = get_user(user_id)

# 业务逻辑2:可能抛出ZeroDivisionError
try:
    discount = calculate_discount(order)
except ZeroDivisionError:
    discount = 0  # 优雅降级,默认折扣为0

# 业务逻辑3:可能抛出FileNotFoundError
try:
    log_order(order)
except FileNotFoundError:
    # 日志记录失败不影响主业务
    pass

6.4 用日志记录完整的异常信息

错误示例

try:
    1 / 0
except ZeroDivisionError as e:
    print(f"错误:{e}")  # 仅打印错误描述,无上下文

解决方案:使用traceback.format_exc()记录完整的栈跟踪信息、业务上下文、用户信息

import logging
import traceback

# 配置日志
logging.basicConfig(
    filename="app.log",
    level=logging.ERROR,
    format="%(asctime)s - %(levelname)s - %(user_id)s - %(order_id)s - %(message)s"
)

try:
    order = get_order(order_id)
    result = process_order(order)
    logging.info(f"订单处理成功", extra={"user_id": order.user_id, "order_id": order.id})
except Exception as e:
    logging.error(
        f"订单处理失败:{traceback.format_exc()}",
        extra={"user_id": order.user_id if "order" in locals() else "未知", "order_id": order_id}
    )

6.5 实现重试机制

对于网络超时、临时资源不足等可重试的异常,应实现指数退避重试机制(如tenacity库):

6.5.1 使用tenacity库实现重试
pip install tenacity  # 安装tenacity
from tenacity import retry, stop_after_attempt, wait_exponential
import requests

# 重试配置:最多3次,每次重试间隔2^1=2s、2^2=4s、2^3=8s
@retry(
    stop=stop_after_attempt(3),
    wait=wait_exponential(multiplier=2),
    retry_on_exception=lambda e: isinstance(e, (requests.Timeout, requests.ConnectionError))
)
def fetch_url(url):
    return requests.get(url, timeout=1).text

try:
    result = fetch_url("http://slow.com")
    print(f"请求成功:{result[:50]}")
except Exception as e:
    print(f"请求失败(3次重试后):{e}")

6.6 统一异常响应格式

Web 应用中,应为所有异常返回统一的 JSON 格式响应,提升前端的处理效率:

Flask 示例

from flask import Flask, jsonify
import traceback

app = Flask(__name__)

# 自定义业务异常
class InsufficientBalance(Exception):
    pass

# 全局异常处理器
@app.errorhandler(Exception)
def handle_exception(e):
    # 业务异常:返回400
    if isinstance(e, InsufficientBalance):
        return jsonify({
            "code": 400,
            "message": str(e),
            "detail": ""
        }), 400
    # 系统异常:返回500,记录日志
    elif isinstance(e, Exception):
        app.logger.error(f"系统错误:{traceback.format_exc()}")
        return jsonify({
            "code": 500,
            "message": "服务器内部错误,请稍后重试",
            "detail": ""
        }), 500

# 测试接口
@app.route("/pay/<order_id>")
def pay(order_id):
    raise InsufficientBalance("用户余额不足")

if __name__ == "__main__":
    app.run()

请求响应

{"code": 400, "message": "用户余额不足", "detail": ""}

6.7 异常的监控与告警

生产环境中,需实时监控异常并及时告警:

  • 监控工具:Sentry(Python 异常监控)、Prometheus+Grafana(指标监控);
  • 告警规则:如 5 分钟内ValueError超过 100 次,或出现OutOfMemoryError时,立即告警;
  • 告警渠道:邮件、短信、企业微信、Slack。

七、异常处理避坑指南

7.1 坑点 1:捕获BaseException导致无法退出

错误代码

try:
    while True:
        pass
except BaseException:
    # 捕获了KeyboardInterrupt(Ctrl+C),无法中断程序
    print("发生错误")

解决方案:仅捕获Exception,或单独处理KeyboardInterrupt

7.2 坑点 2:在finally中返回导致异常丢失

错误代码

def func():
    try:
        1 / 0
    except ZeroDivisionError:
        print("除数为0")
        raise  # 重新抛出异常
    finally:
        return "finally返回值"  # 覆盖了异常

print(func())  # 输出:finally返回值,异常丢失!

解决方案finally块中不要返回值,仅用于资源清理。

7.3 坑点 3:with语句中未处理异常

错误代码

with open("test.txt", "r") as f:
    content = f.read()
    # 这里的异常会被with自动处理,但不会记录日志

解决方案:将with语句放在try-except块中,记录异常。

7.4 坑点 4:异步 Task 的异常未处理

错误代码

async def task():
    raise ValueError("Task失败")

async def main():
    task_obj = asyncio.create_task(task())
    await asyncio.sleep(1)
    print("主函数完成")

asyncio.run(main())  # 输出:主函数完成,Task的异常被忽略!

解决方案:使用asyncio.gather()task_obj.result()处理 Task 的异常。

7.5 坑点 5:自定义异常未继承Exception

错误代码

class MyError(BaseException):  # 继承自BaseException
    pass

解决方案:自定义异常必须继承自Exception


八、实战案例:生产级电商订单系统异常处理

8.1 需求分析

  • 核心功能:订单创建、支付、发货、退款;
  • 异常类型:业务异常(余额不足、订单不存在)、系统异常(支付接口超时、数据库连接失败);
  • 处理要求
    1. 业务异常返回友好提示;
    2. 系统异常记录日志并返回通用错误;
    3. 支付超时实现自动重试;
    4. 异常信息包含订单号、用户 ID 等上下文;
    5. 统一响应格式。

8.2 代码实现(核心部分)

import logging
import traceback
from tenacity import retry, stop_after_attempt, wait_exponential

# -------------------------- 1. 异常定义 --------------------------
class OrderException(Exception):
    def __init__(self, order_id, message):
        super().__init__(message)
        self.order_id = order_id
        self.user_id = None

class OrderNotFoundError(OrderException):
    pass

class InsufficientBalanceError(OrderException):
    pass

class PaymentTimeoutError(OrderException):
    pass

# -------------------------- 2. 日志配置 --------------------------
logging.basicConfig(
    filename="order.log",
    level=logging.ERROR,
    format="%(asctime)s - %(levelname)s - order_id=%(order_id)s - user_id=%(user_id)s - %(message)s"
)

# -------------------------- 3. 支付重试机制 --------------------------
@retry(
    stop=stop_after_attempt(3),
    wait=wait_exponential(multiplier=2),
    retry_on_exception=lambda e: isinstance(e, PaymentTimeoutError)
)
def call_payment_api(order):
    # 模拟支付接口调用,50%概率超时
    import random
    if random.random() > 0.5:
        raise PaymentTimeoutError(order.id, "支付接口超时")
    return {"status": "success", "transaction_id": "TXN2024052001"}

# -------------------------- 4. 订单处理逻辑 --------------------------
def process_order(order):
    try:
        # 1. 检查订单是否存在
        if not order:
            raise OrderNotFoundError(None, "订单不存在")
        
        # 2. 检查余额
        if order.user_balance < order.amount:
            raise InsufficientBalanceError(order.id, "用户余额不足")
        
        # 3. 调用支付接口(带重试)
        payment_result = call_payment_api(order)
        if payment_result["status"] != "success":
            raise OrderException(order.id, "支付失败")
        
        # 4. 更新订单状态
        order.status = "paid"
        update_order(order)
        
        return {"code": 200, "message": "订单支付成功", "data": {"order_id": order.id}}
    
    except (OrderNotFoundError, InsufficientBalanceError) as e:
        # 业务异常:返回友好提示
        e.user_id = order.user_id if order else "未知"
        return {"code": 400, "message": str(e), "data": {}}
    
    except PaymentTimeoutError as e:
        # 系统异常:记录日志
        e.user_id = order.user_id
        logging.error(
            f"支付超时:{traceback.format_exc()}",
            extra={"order_id": e.order_id, "user_id": e.user_id}
        )
        return {"code": 500, "message": "支付超时,请稍后重试", "data": {}}
    
    except Exception as e:
        # 其他系统异常:记录日志
        order_id = order.id if order else "未知"
        user_id = order.user_id if order else "未知"
        logging.error(
            f"系统错误:{traceback.format_exc()}",
            extra={"order_id": order_id, "user_id": user_id}
        )
        return {"code": 500, "message": "服务器内部错误", "data": {}}

# -------------------------- 5. 模拟测试 --------------------------
class Order:
    def __init__(self, id, user_id, amount, user_balance):
        self.id = id
        self.user_id = user_id
        self.amount = amount
        self.user_balance = user_balance
        self.status = "pending"

# 测试用订单:余额不足
order1 = Order("OD2024052001", "USER001", 1000, 500)
# 测试用订单:支付超时
order2 = Order("OD2024052002", "USER002", 500, 2000)

print("订单1处理结果:", process_order(order1))
print("订单2处理结果:", process_order(order2))

8.3 运行结果

订单1处理结果: {'code': 400, 'message': '[订单号:OD2024052001] 用户余额不足', 'data': {}}
订单2处理结果: {'code': 500, 'message': '支付超时,请稍后重试', 'data': {}}

# 日志内容(order.log):
2024-05-20 17:00:00,456 - ERROR - order_id=OD2024052002 - user_id=USER002 - 支付超时:Traceback (most recent call last):
...(完整栈跟踪)
PaymentTimeoutError: [订单号:OD2024052002] 支付接口超时

九、总结

Python 异常处理是系统稳定性的核心保障,从基础的try-except语法到高级的异常链、异步异常、工程化实践,每一个细节都影响着系统的可靠性。

核心原则

  1. 不吞异常:至少记录日志或重新抛出;
  2. 细粒度捕获:仅捕获必要的异常;
  3. 保留上下文:用raise...from保留原始异常信息;
  4. 业务化异常:用自定义异常明确业务错误;
  5. 工程化处理:日志、重试、监控、统一响应一个都不能少。

掌握这些原则和实践,你将写出更稳定、更易维护、更可靠的 Python 代码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值