异步编程如何获取返回值 通过await关键字等待协程执行结束完全指南|Duuu笔记
await后必须是可等待对象,否则报TypeError;协程函数调用返回coroutine对象,需await才执行;不可在普通函数或模块顶层直接使用await;并发需用asyncio.gather()或create_task()。
await 后面必须是可等待对象,否则报
TypeError: object X can't be used in 'await' expression
协程函数调用后返回的是一个
coroutine
对象,不是直接的值;直接 print 或赋值不会触发执行。常见错误是忘了加
await
,或者误把普通函数、列表、
None
丢给
await
。
✅ 正确:调用协程函数后立刻
await
,如
await fetch_data()
❌ 错误:写成
await fetch_data
(没加括号,得到的是函数对象)
❌ 错误:写成
await [1, 2]
或
await result
(result 是已执行完的变量,不是协程)
⚠️ 注意:
asyncio.run()
内部会自动 await 顶层协程,但函数内部仍需显式 await 子协程
在
async def
函数里,return 的值就是
await
的返回值
协程函数的
return
不是“返回给函数”,而是“作为 await 表达式的求值结果”。这和同步函数一致,但容易因异步表象产生误解。
写
return 42
,外面
val = await my_coro()
后,
val
就是
42
不写
return
,默认返回
None
,
await
结果也是
None
抛出异常时,
await
会直接把异常冒泡出来,和同步 raise 行为一致
示例:
async def get_user_id():
return 1001
user_id = await get_user_id() # user_id 是 int 类型,值为 1001
不能在普通函数或模块顶层直接用
await
,会报
SyntaxError: 'await' outside async function
await
是语法关键字,只允许出现在
async def
定义的函数体内。想在脚本开头、交互式环境或同步逻辑里取协程返回值,得靠事件循环驱动。
“
Python免费学习笔记(深入)
”;
ima.copilot
腾讯大混元模型推出的智能工作台产品,提供知识库管理、AI问答、智能写作等功能
下载
✅ 在脚本中:用
asyncio.run(main())
包一层
async
入口函数
✅ 在 IPython/Jupyter 中:启用
%autoawait
或用
await coro
(需已进入 async 模式)
❌ 直接写
await asyncio.sleep(1)
在 .py 文件最外层 —— 语法错误
⚠️ 注意:
asyncio.run()
每次调用都会新建事件循环,不能在已有运行中的 loop 里重复调用(比如 Flask 或 FastAPI 的请求处理中)
并发多个协程时,
await
单个会阻塞,要用
asyncio.gather()
或
asyncio.create_task()
连续写多个
await
是串行的,哪怕它们本身不互相依赖。想真正并发并收集返回值,必须把协程对象提前构造成任务,再统一 await。
❌ 串行写法(慢):
res1 = await fetch_a(); res2 = await fetch_b()
✅ 并发写法(快):
res1, res2 = await asyncio.gather(fetch_a(), fetch_b())
✅ 更灵活写法:
task1 = asyncio.create_task(fetch_a()); task2 = asyncio.create_task(fetch_b()); res1 = await task1; res2 = await task2
⚠️
gather()
遇到任一异常默认取消其余任务;如需“失败不中断”,加参数
return_exceptions=True
实际写异步代码时,最常卡住的地方不是语法,而是混淆“协程对象”和“协程返回值”——前者是待执行的计划,后者是 await 执行完才有的东西。只要盯住每个
await
右边是不是一个真正的
coroutine
对象,基本就不会掉坑里。
