Python使用Ipywidgets与Asyncio时如何获取Future对象中的文件上传数据
问题原因
- 你没有用
await等待Future对象完成就直接访问,asyncio.ensure_future仅负责将任务提交到事件循环调度,不会阻塞等待执行结果,此时用户还未完成上传操作,Future自然处于pending状态 asyncio.run()会创建独立的全新事件循环,和Jupyter环境本身运行的事件循环、widget组件绑定的循环不互通,任务状态无法同步,且asyncio.run()执行完成后会直接销毁创建的循环,根本等不到用户交互操作的触发
解决方案
直接在main函数中await文件上传的Future对象,同时不要使用asyncio.run()启动任务,Jupyter环境自带运行中的事件循环,直接await协程即可。
修改后的可运行代码如下:
import ipywidgets as widgets from IPython.display import display, Markdown import asyncio import nest_asyncio import pandas as pd from io import BytesIO # 适配Jupyter Lab的事件循环 nest_asyncio.apply() # 组件初始化 output = widgets.Output(clear_output=True) upload = widgets.FileUpload() @output.capture(clear_output=True) def file_upload(widget): ''' 绑定组件值变化和Future对象 ''' future = asyncio.Future() @output.capture(clear_output=True) def on_value_change(change): ''' 组件值更新时触发,给Future赋值 ''' future.set_result(widget.value) widget.unobserve(on_value_change) widget.observe(on_value_change, names='value') return future async def main(): # 等待用户上传完成,拿到返回的文件字典 file_content = await file_upload(upload) # 直接在当前上下文使用结果,无需全局变量 print("上传的文件数据:", file_content) # 后续CSV处理逻辑直接写在这里 for filename, data in file_content.items(): df = pd.read_csv(BytesIO(data['content'])) print(f"文件{filename}解析结果:") display(df) display(upload, output) # 直接await运行协程,无需asyncio.run await main()
如果你的Jupyter版本不支持单元格直接await,可以替换最后一行调用逻辑为:
loop = asyncio.get_event_loop() loop.run_until_complete(main())
原理说明
await会暂停当前main协程的执行,直到file_upload返回的Future对象被触发set_result(也就是用户上传文件触发绑定的回调函数时)才会恢复执行,此时拿到的file_content就是完整的上传文件字典,所有后续处理逻辑都可以放在await之后执行,全程不需要依赖全局变量传递数据。
内容的提问来源于stack exchange,提问作者otis1205
相关产品推荐
相关产品推荐

