python 3.10 彻底移除了对 @asyncio.coroutine 装饰器及 yield from 协程的支持,事件循环不再识别生成器为协程,且 asyncio.lock 等同步原语删除了 loop 参数。

asyncio 模块在 Python 3.10 中移除了对旧式协程(基于 @asyncio.coroutine 和 yield from 的生成器协程)的运行时支持,不是“失效”,而是被正式弃用并删除。你如果在 3.10+ 环境中看到 RuntimeWarning: coroutine 'xxx' was never awaited 或直接报 TypeError: object xxx can't be used in 'await' expression,大概率是因为代码混用了两种协程范式。
asyncio.coroutine 装饰器在 3.10 中已被完全移除
Python 3.5 引入async/await 后,@asyncio.coroutine 就进入软弃用;3.10 是硬切割点:
-
@asyncio.coroutine装饰器本身已从asyncio模块中删除,调用会触发AttributeError: module 'asyncio' has no attribute 'coroutine' - 即使你手动保留该装饰器逻辑,底层事件循环也不再识别生成器对象为合法协程 ——
asyncio.run()、await表达式、create_task()全部拒绝接受generator类型 - 所有文档和测试用例均不再覆盖该路径;CPython 源码中相关兼容分支已被清理
如何快速识别代码里还藏着旧协程
重点查这三类模式:- 函数定义含
@asyncio.coroutine装饰器(哪怕只是 import 过) - 函数体里有
yield from asyncio.sleep(...)或yield from some_coro() - 调用链中某处返回的是
types.GeneratorType,却被当成可等待对象传给await或asyncio.create_task()
import inspect
def old_style():
yield from asyncio.sleep(1)
print(inspect.iscoroutinefunction(old_style)) # False
print(inspect.isgeneratorfunction(old_style)) # True
只要输出 True 在第二行,就属于必须重写的旧协程。
asyncio.Lock.acquire() 等方法不再接受 loop 参数
这不是协程语法问题,但常被误认为“API 失效”:- Python 3.10 移除了
asyncio.Lock.__init__(loop=None)和acquire(loop=None)中的loop参数 - 如果你的代码显式写了
lock = asyncio.Lock(loop=loop)或await lock.acquire(loop=loop),会报TypeError: __init__() got an unexpected keyword argument 'loop' - 正确写法是直接
lock = asyncio.Lock(),它自动绑定当前运行的事件循环(由get_running_loop()提供) - 同理,
asyncio.Event、asyncio.Semaphore等同步原语也删掉了loop参数
迁移时最容易忽略的兼容细节
真正卡住人的往往不是语法改写,而是隐式依赖:- 旧协程函数返回的是生成器对象,可能被某些框架(如早期版本的
aiohttp或自定义中间件)当作可调度单元;新协程返回的是coroutine对象,类型检查更严格 -
asyncio.ensure_future()在 3.10 中仍能包装旧生成器(出于向后兼容),但返回的是Future而非Task,行为不一致;应统一改用asyncio.create_task() - 单元测试里若用
mock.AsyncMock模拟旧协程,需确认其side_effect返回的是真正的协程对象,而非模拟的生成器
-Werror::DeprecationWarning,提前暴露残留的过渡期 API 调用。大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











