超类的__init__没有使用dataclass被调用

4

我正在通过继承asyncio.Future类来创建一个作业类,并带有一些自定义属性,期望该作业实例的函数与原始Future相同。

当我在协程中调用job.set_result时,它会引发Future对象未初始化错误,然后我尝试通过调用asyncio.ensure_future来初始化该Future,但是仍然出现相同的错误。

我尝试了更多,并发现通常通过loop.create_future()来创建Future,但是没有选项可以创建我的自定义Future。

以下是一个示例,我该如何让我的自定义Future被初始化?

import asyncio
from dataclasses import dataclass

@dataclass
class Job(asyncio.Future):
    job_task: Callable
    real_future: asyncio.Future = None
    something: str = None

    def schedule(self):
        async def run():
            res = await self.job_task()
            self.set_result(res) # raise error, future not initialized
            return res
        self.real_future = asyncio.ensure_future(run())

async def main():
    async def task():
        await asyncio.sleep(1)
        return 1
    job = Job(task)
    job.schedule()
    await job

asyncio.run(main())


@user4815162342 哇,太棒了!谢谢你,你可以写个回答,这样我就能接受它了。 - BAKE ZQ
2个回答

4

您需要自己调用超类构造函数,这是由于dataclass的__init__由于某些原因无法完成。但您也不应该尝试重新实现__init__,因为它并不是非常直观,而且可能会出错。

正确的方法(假设您仍想继续使用@dataclass装饰器)是利用dataclasses提供的__post_init__钩子:

@dataclass
class Job(asyncio.Future):
    job_task: Callable
    real_future: asyncio.Future = None
    something: str = None

    def __post_init__(self)
        super().__init__()

    def schedule(self):
        async def run():
            res = await self.job_task()
            self.set_result(res)  # works now
            return res
        self.real_future = asyncio.ensure_future(run())

2
问题在于Future不是一个数据类,但是您的Job类继承自它并使用@dataclass修饰符。这导致无法调用Future.__init__,因此无法初始化future对象。
要解决此问题,请首先不要使用@dataclass修饰符。相反,编写一个显式的__init__函数来设置必要的属性,并调用super().__init__()来正确初始化Future

@downvoter 这个回答怎么会“没用”呢?它是作为评论发布的,而且提问者说它解决了他们的问题。当然还有其他方法可以解决这个问题,但如果这个回答确实有错误之处,请写下评论来描述它,这样我就可以改进它。 - user4815162342
这是我,我考虑开启一场讨论但最终决定将我的问题作为回答发布。我认为这并不有用,因为它通过引入不必要的危险来解决问题。 - Arne
@Arne我的回答的意思是一开始就不要使用@dataclass装饰器,用手动的__init__取代它。我现在明白这个意思没有明确表达,可能会被误解为建议编写一个明确的__init__并继续使用@dataclass,这不是我的意图。我已经修改了答案来明确说明。 - user4815162342
啊,好吧。 - Arne

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接