我想确保以下方法中的from_dict
在其子类中也能很好地工作。目前,它的类型不能工作(mymyerror "不兼容的返回值类型")。我想是因为子类返回的是子类的一个实例,而不是超类的一个实例。
from __future__ import annotations
from abc import ABC
from dataclasses import dataclass
from typing import ClassVar, Type
@dataclass
class Statement(ABC):
@classmethod
def from_dict(cls) -> Statement:
return cls()
@dataclass
class Parent(ABC):
SIGNATURE_CLS: ClassVar[Type[Statement]]
def say(self) -> Statement:
# Initialize a Statement through a from_dict classmethod
return self.SIGNATURE_CLS.from_dict()
@dataclass
class ChildStatement(Statement):
pass
@dataclass
class Child(Parent, ABC):
SIGNATURE_CLS = ChildStatement
def say(self) -> ChildStatement:
# Initialize a ChildStatement through a from_dict classmethod
# that ChildStatement inherits from Statement
return self.SIGNATURE_CLS.from_dict()
上面的代码产生这个MyPy错误:
Incompatible return value type (got "Statement", expected "ChildStatement") [return-value]
我认为这是Statement
中TypeVar
的用例,但我不确定如何实现,特别是它背后的含义是什么。
子类实例is根据类型规则,它的超类的一个实例。您看到的错误是因为from_dict
被键入为返回Statement
,并且您试图从say
返回该值,这保证返回ChildStatement
。因此,您的问题是,您可能会返回更通用的Statement
,而期望更具体的ChildStatement
。
你需要以某种方式确保MyPy:
from_dict
返回它的实际类,而不是通用的Statement
。Child
的SIGNATURE_CLS
将是ChildStatement
,而不可能是Statement
(仅仅分配ChildStatement
是不够的,因为您显式地将其键入ClassVar[Type[Statement]]
你可以用下面的代码来完成:
- 使用打字。自我反映
return cls()
from typing import Self
@dataclass
class Statement(ABC):
@classmethod
def from_dict(cls) -> Self:
return cls()
(重要的是要注意typing.Self
是Python 3.11中引入的一个非常新的添加,您可能还需要更新您的MyPy以能够考虑到这一点)
- 显式键入
Child.SIGNATURE_CLS
@dataclass
class Child(Parent, ABC):
SIGNATURE_CLS : ClassVar[Type[ChildStatement]] = ChildStatement
最后,我想知道Statement.from_dict()
方法的敏感性,因为它与使用Statement()
的标准构造函数没有什么不同。