super class 的 __init__ 未使用数据 class 调用

super class's __init__ is not called using dataclass

我正在通过从 asyncio.Future 继承一些自定义属性来创建作业 class,并希望作业实例像原始 Future 一样运行。

当我在协同程序中调用 job.set_result 时,它引发了一个 Future object is not initialized error,然后我尝试通过调用 asyncio.ensure_future 来初始化未来,但出现了同样的错误。

我尝试了更多,发现 future 通常是由 loop.create_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())

问题是 Future 不是数据 class,但是您的 Job class 继承自它并使用 @dataclass 装饰器。这会导致无法调用 Future.__init__ 并因此无法初始化未来对象。

要解决此问题,请不要在第一个部分使用 @dataclass 装饰器 地方。相反,编写一个明确的 __init__ 来设置必要的属性,并调用 super().__init__() 来正确初始化 Future

您需要自己调用超类构造函数,这是数据类 __init__ 无法做到的 because of reasons. But you also shouldn't try to re-implement __init__ yourself, since it is not exactly intuitive,您可能会搞砸。

正确的做法(假设您想继续使用 @dataclass 装饰器)是利用数据类提供的 __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())