异步执行@classmethod类方法报错:协程未被等待,如何修复?
问题描述
我编写了一个testMethod类,用于获取当前工作目录下的文件路径,其中包含一个用@classmethod装饰的异步方法,意图异步读取目录下的文件。代码如下:
import os import asyncio import aiofiles import json class testMethod: def __init__(self, path): self._path = path def getFile(self): file = os.path.join(os.path.dirname(os.path.abspath(__file__)), self._path) return file @classmethod async def asyncFile(cls, type: str = 'json', *args, **kwargs): super(cls).__init__(*args, **kwargs) self = asyncio.get_event_loop() async def param(): if type == 'json': js_file = cls('args.json').getFile() async with aiofiles.open(js_file, 'r') as f: params = json.load( await f) return params def run(): return self.run_until_complete(param()) return run()
调用时出现以下错误:
<coroutine object testMethod.asyncFile at 0x7fc1b8ffa5c0>
sys:1: RuntimeWarning: coroutine 'testMethod.asyncFile' was never awaited
我知道错误和未正确使用await或事件循环处理有关,想知道遗漏了哪些关键步骤。期望实现如下调用并直接输出JSON内容:
b = testMethod('some_path.json').asyncFile() print(b) # 预期输出 # <some json content>
问题分析与修正方案
你的代码存在几个核心问题,导致异步逻辑无法正确执行:
- 异步方法调用逻辑错误:被
async修饰的方法调用后会返回协程对象,必须通过await或事件循环驱动执行,但你直接调用后未处理该协程。 - 类方法与实例逻辑混淆:
asyncFile被标记为@classmethod,但你试图在其中调用父类构造super(cls).__init__,这是错误的——类方法不需要实例化,也不能这么调用构造方法;同时你期望用实例调用该方法,违背了类方法的设计意图。 - 事件循环错误使用:在异步方法内部手动创建事件循环并调用
run_until_complete是冗余且错误的,异步方法本身需要由外部事件循环调度执行。 - JSON读取逻辑错误:
json.load(await f)用法错误,json.load接收文件对象,而await f返回的是字符串内容,应该用json.loads解析。
修正后的代码
根据你期望的调用方式,调整逻辑如下:将asyncFile改为实例方法,内部封装异步逻辑与事件循环启动逻辑,确保同步调用即可获取结果:
import os import asyncio import aiofiles import json class testMethod: def __init__(self, path): self._path = path def getFile(self): file = os.path.join(os.path.dirname(os.path.abspath(__file__)), self._path) return file def asyncFile(self, file_type: str = 'json'): # 封装异步读取逻辑 async def read_file(): if file_type == 'json': js_file = self.getFile() async with aiofiles.open(js_file, 'r', encoding='utf-8') as f: content = await f.read() return json.loads(content) # 启动事件循环执行异步任务 return asyncio.run(read_file())
调用方式
现在可以按照你期望的方式调用,直接获取并打印JSON内容:
b = testMethod('some_path.json').asyncFile() print(b)
关键修正点说明
- 移除
@classmethod装饰器,将asyncFile改为实例方法,直接使用初始化时传入的_path参数,匹配你调用时传入文件路径的需求。 - 用
asyncio.run()统一管理事件循环,替代手动创建循环的冗余逻辑,这是Python 3.7+推荐的异步任务启动方式。 - 修正JSON读取逻辑,先通过
await f.read()获取文件字符串内容,再用json.loads()解析为JSON对象。
内容的提问来源于stack exchange,提问作者joe_bill.dollar
相关产品推荐
相关产品推荐

