You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

异步执行@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)

关键修正点说明

  1. 移除@classmethod装饰器,将asyncFile改为实例方法,直接使用初始化时传入的_path参数,匹配你调用时传入文件路径的需求。
  2. 用asyncio.run()统一管理事件循环,替代手动创建循环的冗余逻辑,这是Python 3.7+推荐的异步任务启动方式。
  3. 修正JSON读取逻辑,先通过await f.read()获取文件字符串内容,再用json.loads()解析为JSON对象。

内容的提问来源于stack exchange,提问作者joe_bill.dollar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 23:31:17