如何使抽象数据类通过mypy?

16

mypy v0.910在Python 3.9中拒绝抽象数据类。这是一个最小可重现的示例:

from abc import ABC, abstractmethod
from dataclasses import dataclass

@dataclass
class Liquid(ABC):

    @abstractmethod
    def drip(self) -> None:
        pass

这是错误信息:

$ mypy --python-version 3.9 so.py
so.py:4: error: Only concrete class can be given where "Type[Liquid]" is expected
Found 1 error in 1 file (checked 1 source file)

我该如何让这段代码通过 mypy


我从mypy问题#5374中了解到,这是一个在2018年首次注意到并仍未得到纠正的mypy错误。但我认为人们必须使用mypy与抽象数据类,因此必须有一种解决方法或正确的定义或注释类的方式。有何建议?

错误消息的基础似乎是mypy假定任何类型为Type的对象都可以实例化,但是抽象类不能实例化。由于Type定义为意味着一个类对象,并不一定是一个具体的类对象(即可以实例化的对象),这似乎是错误的原因。

在包含class Liquid的行中添加# type: ignore无法阻止错误消息。由于代码中不包含Type[Liquid],我认为它必须是dataclass生成的代码中。在Python 3.9中,Type已弃用,但显然dataclass代码生成器仍会生成它。


1
好奇一下,在这里使用dataclass装饰器的目的是什么? - juanpa.arrivillaga
1
@juanpa.arrivillaga 目的只是为了创建一个最小可重现的示例。我的生产代码中的数据类具有成员属性。我刚刚仔细检查了一下,如果我添加成员属性,示例确实会失败。 - Ben Kovitz
3个回答

11

创建一个数据类作为混合类,然后让ABC从它继承:

from abc import ABC, abstractmethod
from dataclasses import dataclass    

@dataclass
class LiquidDataclassMixin:
    my_var: str

class Liquid(ABC, LiquidDataclassMixin):
    @abstractmethod
    def drip(self) -> None:
        pass

这也适用于我的mypy类型检查。我建议不要使用# type: ignore,因为那样会破坏类型检查的目的。引自此GitHub问题


当我第一次看到这种方法时,我担心它会创建混乱,因为每个抽象数据类都需要一个单独的mix-in类。但是我已经检查了我整个代码库,只发现了四个抽象数据类,所以这肯定可行。谢谢! - Ben Kovitz
我刚刚取消了这个答案的采纳,因为在这个问题中有一个问题被解释了。我更喜欢保持类型检查,所以如果你(或任何人)能告诉我如何避免这个问题,我会重新接受这个答案。我还在那里发布了一个解决方案,并附有说明。请看一下,看看你的想法。 - Ben Kovitz
说,将ABC放在LiquidDataclassMixin之前的原因是什么?这可能是谜题中至关重要的一部分。 - Ben Kovitz

3
在装饰器行中添加# type: ignore。在您的情况下,应该是这样的:
from abc import ABC, abstractmethod
from dataclasses import dataclass

@dataclass  # type: ignore[misc]
class Liquid(ABC):

    @abstractmethod
    def drip(self) -> None:
        pass

1
经过更多的编码和遇到更多问题后,我决定在装饰器行中关闭类型检查确实是正确的解决方案,正如这个答案所解释的那样。如果您将 type: ignore 更改为 type: ignore[misc],我会接受这个答案。(如果我很快没有收到您的回复,我自己会进行编辑。) - Ben Kovitz
1
已矫正。感谢您的更新,很抱歉回复晚了 :) - Kamil Tagowski

1

谢谢!当v0.983推出时,看起来这将是获胜的答案。 - Ben Kovitz
v0.991已发布,其中包含了"type-abstract"的更新。 - Moore

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