Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

super class's __init__ is not called using dataclass

I am making a job class by inheriting from asyncio.Future with some custom attributes, and expect the job instance functions like the original Future.

When I call job.set_result inside a coroutine, it raises a Future object is not initialized error, then I tried to get future initialized by call asyncio.ensure_future and the same error appears.

I tried more and find that the future is usually created by loop.create_future(), however, there is no options to create my custom future.

Below is an example, How can I get my custom future initialized?

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())

like image 939
BAKE ZQ Avatar asked Oct 20 '25 13:10

BAKE ZQ


2 Answers

You need to call the superclass constructor yourself, something that dataclass's __init__ can't do because of reasons. But you also shouldn't try to re-implement __init__ yourself, since it is not exactly intuitive and you might mess up.

The Right Way To Do It (given that you want to keep using the @dataclass decorator) is leveraging the __post_init__ hook that dataclasses provide:

@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())
like image 116
Arne Avatar answered Oct 23 '25 04:10

Arne


The problem is that Future is not a dataclass, but your Job class inherits from it and uses the @dataclass decorator. This results in failure to invoke Future.__init__ and consequently failure to initialize the future object.

To fix the issue, don't use the @dataclass decorator in the first place. Instead, write an explicit __init__ that sets the necessary attributes, and invokes super().__init__() to initialize the Future correctly.

like image 28
user4815162342 Avatar answered Oct 23 '25 04:10

user4815162342



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!