Python 3.12 正式移除 @coroutine 装饰器,强制要求将旧式生成器协程迁移到 async def 范式;所有含 yield/yield from 的 @coroutine 函数须重写为 async def 并用 await 替代,无真实异步操作则应改回普通函数。

Python 3.12 正式移除了 @coroutine 装饰器(来自 asyncio),任何仍显式使用它的代码会直接抛出 NameError: name 'coroutine' is not defined 或导入失败。这不是警告,是硬性删除 —— 没有兼容层,也没法“临时降级绕过”。必须改。
为什么 @coroutine 被删了?
它早在 Python 3.5 引入 async/await 后就进入弃用状态,仅用于包装生成器使其被 asyncio 当作协程识别。到 3.12,所有旧式生成器协程(yield-based)已完全不被事件循环接受,@coroutine 失去存在意义。
关键点:你不是在“修复装饰器”,而是在把一段本就不该再存在的模式,迁移到现代协程范式。
async def 是唯一合法替代方案
所有曾用 @coroutine 包裹的函数,必须重写为 async def 函数。不能只改装饰器,也不能靠类型提示或返回值伪装。
立即学习“Python免费学习笔记(深入)”;
安全 Python 代码沙箱:在隔离的沙箱中执行任意 Python 代码,预装 requests、NumPy、pandas 库。返回 stdout、stderr。
- 错误写法:
@asyncio.coroutine→ 改成@asyncio.coroutines.coroutine(不存在)或@types.coroutine(不生效) - 正确路径:把函数体里的
yield from、yield全部替换为await,函数声明改为async def - 如果函数内部没真正 await 任何协程(比如只是同步逻辑),那它根本不需要是协程 —— 直接去掉
async和await,当普通函数用
示例对比:
# Python 3.11 及以前(已失效)
@asyncio.coroutine
def fetch_data():
yield from asyncio.sleep(1)
return "done"
<h1>Python 3.12 正确写法</h1><p>async def fetch_data():
await asyncio.sleep(1)
return "done"</p>第三方库还在用 @coroutine 怎么办?
检查依赖版本 —— 这是典型信号:你正在用一个未适配 Python 3.12 的老库(比如某些 aiomysql aioredis
- 优先升级:运行
pip install --upgrade <package></package>,确认其最新版声明支持 Python 3.12 - 查 GitHub issues:搜
"Python 3.12 coroutine",看是否已有 PR 修复或用户反馈 - 临时规避(不推荐):若无法升级,只能 fork 该库,手动将
@coroutine替换为async def并修复内部yield逻辑 —— 但大概率会牵扯底层协议适配,风险高
容易忽略的隐藏调用点
有些代码不会直接写 @coroutine,却因间接依赖触发报错,比如:
- 自定义的基类里有
asyncio.coroutine导入并用于装饰方法 - 测试框架(如
pytest-asyncio旧版)的 fixture 声明用了该装饰器 - 项目里混用了
asyncio.Task构造时传入旧式生成器协程(asyncio.create_task(old_style_coro()))
排查建议:全局搜索 from asyncio import coroutine、import asyncio 后跟 asyncio.coroutine、以及所有 yield from 出现的位置。这些地方都得动。
真正麻烦的不是语法改写,而是那些把 yield 当协程调度点、混用同步/异步状态机的旧逻辑 —— 它们在 3.12 下不会报错提示“请改 async”,而是直接崩在事件循环启动阶段。动手前,先确保你清楚每个函数到底需不需要异步语义。

















