gpt4 book ai didi

python - mypy:如何将返回值定义为子类实例列表

转载 作者:行者123 更新时间:2023-12-04 12:24:51 26 4
gpt4 key购买 nike

我正在尝试定义方法 foo 的返回值作为 AbstractChild 的列表子类实例,但 mypy 一直给我一个错误。

class AbstractParent(ABC):
@abstractmethod
def foo(self) -> List["AbstractChild"]: pass


class AbstractChild(ABC):
pass


class Parent(AbstractParent):
def foo(self) -> List["Child"]: pass
# ^ mypy: error Return type "List[Child]" of "foo" incompatible with return type "List[AbstractChild]" in supertype "AbstractParent"


class Child(AbstractChild):
pass

将列表中的返回类型更改为单个值将使 mypy 停止提示,我觉得这很奇怪,但我仍然习惯了 python 类型系统,所以我可能会遗漏一些东西。

最佳答案

mypy在这里是正确的,因为您的 Parent不实现 AbstractParent正确 - 要做到这一点,它应该定义一个方法 foo返回 AbstractChild 的列表仁,不是 Child仁。这是因为集合不是多态的(这对于其他语言也是如此,例如 Java):List[AbstractChild]List[Child] 的类型不同, 和 List[Child]不继承自 List[AbstractChild]只是因为Child做。如果我们没有这个限制,可能会出现这样的错误:

class AbstractChild(ABC):
pass

class Child(AbstractChild):
pass

class GrandChild(AbstractChild):
pass

grandchildren: List[GrandChild] = [GrandChild()]
all_children: List[AbstractChild] = grandchildren
all_children.append(Child())
grandchild: GrandChild = grandchildren[0] # would pass typechecks but is a Child, actually

(这是 Jon Skeet's answer for a similar question in Java 的改写示例)。

例如,Java 在编译时捕获这种类型的错误并需要显式协方差,例如 List<? extends Child>用于阅读和 List<? super Child>用于写入列表。

在您的情况下,您还将引入泛型类型。在下面的示例中,我更改了 AbstractParent返回 List具有相同类型的元素 C可以是任何子类 AbstractChild , 和 Parent是泛型 AbstractChild 的具体实现带具体子类型 Child :
from typing import List, TypeVar, Generic


C = TypeVar('C', bound='AbstractChild')


class AbstractParent(ABC, Generic[C]):
@abstractmethod
def foo(self) -> List[C]: pass


class Parent(AbstractParent["Child"]):
def foo(self) -> List["Child"]:
return []

有关更多示例,请查看 Generics章来自 mypy文档,特别是 Variance of generic types部分。

关于python - mypy:如何将返回值定义为子类实例列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60251943/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com