1. 异常是什么? #

2. 基本语法 #

# 尝试转换输入并做除法
try:
    user_input = input("请输入一个数字: ")
    age = int(user_input)
    result = 100 / age
    print(result)
# 捕获值错误(如输入非数字)
except ValueError:
    print("请输入数字")
# 捕获除零错误
except ZeroDivisionError:
    print("不能为 0")
# 导入logging模块,用于日志记录
import logging
# 获取当前模块的logger对象
logger = logging.getLogger(__name__)
# 捕获具体业务异常和通用异常
# 定义一个用户不存在的异常类,继承自Exception
class UserNotFoundError(Exception):
    pass
# 定义一个获取用户数据的函数
def fetch_user(user_id):
    # 伪实现:如果用户id为1则存在,否则抛异常
    if user_id == 1:
        # 如果用户id等于1,返回用户信息字典
        return {"id": 1, "name": "用户A"}
    else:
        # 否则抛出用户不存在异常
        raise UserNotFoundError()

# 定义用于获取用户信息并处理异常的函数
def get_user(user_id):
    try:
        # 调用fetch_user函数获取用户数据
        data = fetch_user(user_id)
        # 如果获取成功,返回数据和200状态码
        return {"data": data}, 200
    # 捕获用户不存在的异常
    except UserNotFoundError:
        # 返回错误信息和404状态码
        return {"error": "用户不存在"}, 404
    # 捕获其他未知异常
    except Exception:
        # 记录异常堆栈信息
        logger.exception("未知错误")
        # 返回服务器错误信息和500状态码
        return {"error": "服务器错误"}, 500

# 打印获取用户id为1的结果,应该返回200
print(get_user(1))   # 应该返回200
# 打印获取用户id为2的结果,应该返回404
print(get_user(2))   # 应该返回404

2.1 else 与 finally #

# try/except/else/finally 完整结构
try:
    f = open("data.txt", encoding="utf-8")
except FileNotFoundError:
    print("文件不存在")
else:
    # 仅无异常时执行
    print("仅无异常时执行", f.read())
finally:
    # 无论是否异常都会执行
    print("无论是否异常都会执行")

3. 常见内置异常 #

异常 典型原因
ValueError 值不合法,如 int("abc")
TypeError 类型不对,如 "1" + 1
KeyError 字典缺少键
IndexError 下标越界
FileNotFoundError 文件不存在
PermissionError 无权限
AttributeError 属性/方法不存在
ZeroDivisionError 除零

4. 主动抛出:raise #

# 定义一个数据库类 DB
class DB:
    # 初始化方法,定义用户数据
    def __init__(self):
        # 设置一个包含两个用户信息的字典
        self.users = {1: {"id": 1, "name": "Alice"}, 2: {"id": 2, "name": "Bob"}}
    # 查找用户的方法,根据用户ID返回用户数据
    def find(self, user_id):
        # 从 users 字典中获取对应 user_id 的用户数据
        return self.users.get(user_id)

# 自定义一个异常类 UserNotFoundError,继承自 Exception
class UserNotFoundError(Exception):
    # 占位符,表示无需额外实现
    pass

# 创建 DB 的实例,赋值给变量 db
db = DB()

# 定义获取用户信息的方法,输入参数为用户 ID,类型为 int
def get_user(user_id: int):
    # 判断用户 ID 是否小于等于 0
    if user_id <= 0:
        # 如果用户 ID 小于等于 0,抛出 ValueError 异常
        raise ValueError("用户 ID 必须大于 0")
    # 调用 db 的 find 方法查找用户
    user = db.find(user_id)
    # 判断用户是否存在
    if not user:
        # 如果用户不存在,抛出 UserNotFoundError 异常
        raise UserNotFoundError(f"用户 {user_id} 不存在")
    # 返回找到的用户信息
    return user

5. 在 except 里重新 raise #

# 导入日志模块
import logging

# 定义自定义数据库异常
class DatabaseError(Exception):
    pass

# 定义处理函数
def process(data):
    # 尝试运行,抛出数据库异常
    try:
        raise DatabaseError("数据库操作失败")
    # 捕获数据库异常后,重新抛出
    except DatabaseError:
        raise

# 获取logger对象
logger = logging.getLogger(__name__)
# 配置日志输出级别为ERROR
logging.basicConfig(level=logging.ERROR)

# 定义原始数据
raw = "测试数据"
# 尝试处理数据
try:        
    process(raw)
# 捕获数据库异常
except DatabaseError:
    # 输出错误日志并包含异常堆栈信息
    logger.error("数据库失败", exc_info=True)

6. 异常链 #

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

def order_service():
    try:
        # 假设下单时调用库存系统,代码处可能会抛 OSError
        raise OSError("库存系统连接失败")
    except OSError as e:
        # 包装底层 OSError,形成异常链
        raise BusinessError("下单失败") from e

try:
    order_service()
except BusinessError as e:
    print("捕获到业务异常:", e)
    print("底层原因:", e.__cause__)

7. 自定义异常 #

# 项目业务异常基类
class AppError(Exception):
    pass

# 用户不存在异常
class UserNotFoundError(AppError):
    pass

# 支付失败异常,携带订单 ID
class PaymentFailedError(AppError):
    def __init__(self, order_id: str, reason: str):
        self.order_id = order_id
        self.reason = reason
        super().__init__(f"Order {order_id} payment failed: {reason}")

try:
    raise UserNotFoundError("用户不存在")
except UserNotFoundError as e:
    print(f"Caught UserNotFoundError: {e}")
try:
    raise PaymentFailedError("12345", "余额不足")
except PaymentFailedError as e:
    print(f"Caught PaymentFailedError: {e}, order_id: {e.order_id}, reason: {e.reason}")

8. Web 中的处理方式 #

# 业务层抛自定义异常,入口统一映射 HTTP 状态码

class UserNotFoundError(Exception):
    pass

def get_user(user_id: int):
    # 简单模拟业务逻辑
    if not isinstance(user_id, int) or user_id <= 0:
        raise ValueError("user_id 必须为正整数")
    if user_id != 1:
        raise UserNotFoundError(f"用户 {user_id} 未找到")
    # 假设只有id为1的用户存在
    return {"id": 1, "name": "张三"}

def get_user_api(user_id: int):
    try:
        # 假设 get_user 是业务逻辑层的方法,可能抛出 UserNotFoundError 或 ValueError
        return {"data": get_user(user_id)}
    except UserNotFoundError as e:
        # 用户未找到,返回 404
        return {"error": str(e)}, 404
    except ValueError as e:
        # 参数非法,返回 400
        return {"error": str(e)}, 400
    except Exception as e:
        # 其他未知异常,返回 500
        return {"error": "Internal Server Error: " + str(e)}, 500

print(get_user_api(1))

9. 项目开发要点 #

10. 总结 #

语法 用途
try / except 捕获并处理错误
raise 主动报错、校验失败
自定义异常类 区分业务错误与系统错误
with 自动释放文件等资源
日志 + 重新 raise 记录后交给上层或统一处理器