装饰器中异常捕获需在内层函数用 try/except 包裹 func(args, *kwargs),保留返回值、捕获 exception 而非裸 except,并用 @functools.wraps(func) 保持原函数元信息;异步函数需专用 async wrapper。

装饰器里怎么写异常捕获逻辑
核心是用 try/except 包住 func(*args, **kwargs) 调用,再把异常处理逻辑(比如记录日志、返回默认值、重新抛出)放在 except 块里。别直接在装饰器函数体顶层写 try,那会捕获装饰器自身初始化时的错误,不是目标函数的。
常见错误:漏掉 return —— 如果原函数有返回值,但装饰器里没显式返回,就变成 None;或者只处理了部分异常类型,结果 ValueError 捕到了,KeyError 却冒泡出去了。
- 必须保留原函数的返回值:
return func(*args, **kwargs) - 建议捕获
Exception而非裸except:,避免吞掉KeyboardInterrupt或SystemExit - 如果想透传原异常,用
raise不带参数,保持 traceback 不变
如何让装饰器支持自定义异常处理行为
靠闭包加参数。外层函数接收处理策略(如日志级别、默认返回值、是否重试),内层才是真正作用于目标函数的装饰器。这样就能复用同一套异常捕获骨架,适配不同场景。
典型使用场景:API 接口函数统一返回 {"code": 500, "msg": "xxx"};数据清洗函数遇到脏数据时跳过并打日志,不中断流程。
SkillSub Pro - Python 题解与代码注释双功能技能功能概述SkillSub Pro - Python 题解与代码注释双功能技能是一项面向实际任务的技能,主要用于SkillSub Pro 是一个 Python 题解生成与代码注释的 双功能合体技能 ,专为学生、算法学习者和开发者设计;✅ 一个技能,两种用途 :;核心要点📝 题解模式 :输入题目/题号,自动生成完整 Python 题解(含详细注释、解题思路、复杂度分析);💬 注释模式 :输入 Python 代码,自动添加详细中。它将相关步骤、
- 参数命名要直白,比如
default_return=None、log_level="warning" - 避免在装饰器里做耗时操作(如网络请求),否则所有被装饰函数都会被拖慢
- 注意参数默认值别用可变对象(如
default_return=[]),会导致状态跨调用污染
@functools.wraps(func) 为什么不能省
不加它,被装饰函数的 __name__、__doc__、__annotations__ 全都变成内层闭包函数的,调试、IDE 提示、自动文档生成全失效。这不是风格问题,是实际协作中会立刻踩的坑。
错误现象:help(my_func) 显示的是 wrapper 的空文档;用 pytest 测函数名时匹配不到;类型检查工具报 “no type hints found”。
- 必须在内层函数上加
@functools.wraps(func) - 导入别漏:
from functools import wraps - 如果用了多层装饰器(比如先
@retry再@catch_error),每一层都要加wraps
异步函数(async def)怎么用异常装饰器
普通装饰器对 async def 函数无效——它返回的是协程对象,不是直接执行结果。必须写一个专门处理 await 的版本,用 async/await 包裹调用,并在 except 后用 await 执行异步日志等操作。
容易忽略的点:同步日志库(如内置 logging)在异步上下文中可用,但异步日志库(如 aiologger)才真正适配高并发场景;若装饰器里混用阻塞调用(如 time.sleep),会卡住整个 event loop。
- 函数签名得是
async def wrapper(...),内部用await func(...) - 不要用
loop.run_in_executor包同步操作来“打补丁”,这增加复杂度且易出错 - 测试时得用
asyncio.run()或pytest-asyncio,普通assert会直接断言协程对象而非结果
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










