【问题标题】:super class's __init__ is not called using dataclass不使用数据类调用超类的 __init__
【发布时间】:2021-03-27 03:49:42
【问题描述】:

我正在通过使用一些自定义属性从 asyncio.Future 继承来创建作业类,并期望作业实例的功能与原始 Future 一样。

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

我尝试了更多,发现未来通常是由loop.create_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 哇,它成功了。谢谢,你能回答我吗?

标签: python python-3.x python-dataclasses


【解决方案1】:

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

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

【讨论】:

  • @downvoter 这个答案如何“没用” - 它是作为评论发布的,OP 说它解决了他们的问题。可以有其他方法来解决它,但如果这个答案在某些方面实际上是不正确的,那么请写一个评论来描述它,以便我改进它。
  • 是我,我想开始讨论,但决定只发布我的问题作为答案。我认为它没有用,因为它通过引入一些不必要的危险来解决问题。
  • @Arne 我的回答意味着首先不要使用 @dataclass 装饰器,替换它的使用手动 __init__。我现在看到它不是明确的,可能会被误解为建议写一个明确的__init__ 并继续使用@dataclass,这不是我的意图。我现在已经修改了答案以明确说明。
  • 啊,很公平。
【解决方案2】:

您需要自己调用超类构造函数,这是数据类的__init__ 无法做到的because of reasons。但是您也不应该尝试自己重新实现__init__,因为它is not exactly intuitive 可能会搞砸。

正确的做法是利用数据类提供的__post_init__ 钩子(假设您想继续使用@dataclass 装饰器):

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

【讨论】:

    猜你喜欢
    • 2018-12-02
    • 2014-03-07
    • 2012-08-30
    • 2011-04-16
    • 2014-08-15
    • 2017-12-29
    • 2010-11-26
    • 2012-09-20
    • 2021-02-22
    相关资源
    最近更新 更多