mypy 列表中对象继承的问题

问题描述 投票:0回答:2

Python 3.6.5 和 mypy 0.600

我写了代码:

from typing import List


class Animal():
    pass


class Dog(Animal):
    def __init__(self) -> None:
        super()

    def bark(self) -> None:
        pass


class Cat(Animal):
    def __init__(self) -> None:
        super()

    def meow(self) -> None:
        pass


arr1: List[Dog] = [Dog(), Dog()]
arr2: List[Animal] = [Dog(), Dog()]

# error: Incompatible types in assignment (expression has type "List[Dog]", variable has type "List[Animal]")
arr3: List[Animal] = arr1

我不明白,为什么我的变量“arr3”出现“赋值类型不兼容”错误。 Dog 是一个继承自 Animal 的类。 例如,我的变量“arr2”没有错误。

python python-typing mypy
2个回答
10
投票

想象一下这是可能的:

arr3: List[Animal] = arr1

现在你认为你有动物列表,但这实际上是狗列表(请注意,

arr3
不是
arr1
的副本,它们是相同列表)。

因为您认为这是动物列表,所以您可以在其中添加

Cat

但是,因为这实际上是狗的列表,所以您不能在其中添加

Cat
。否则,在尝试使用特定于狗的属性后,您将会失败。

更一般地,列表是不变的 -

AttributeError

不能分配给

List[Animal]
(因为它已经可以包含猫)并且
List[Dog]
不能分配给
List[Dog]
(因为你可以稍后添加猫)

这在Python中可能不明显,但你可以做简单的测试:

List[Animal]

Mypy 不允许这样做,因为此分配可能会破坏您的代码逻辑


6
投票
arr3: List[Animal] = arr1 arr3.append(Cat()) for dog in arr1: print(dog.bark())

这是协变的

Sequence[Animal]

是不变的;它只会处理类型为

List[T]
的项目。这意味着
T
不是
List[Dog] 的子类型。这是因为 @awesoon 提到的,它可以防止您意外添加与 T 不兼容的项目:
List[Animal]

另一方面,
# this won't compile: dogs : List[Dog] = [dog1, dog2] animals : List[Animal] = dogs # compiler error: List is invariant # if the compiler allowed the previous line, # then `dogs` would be [dog1, dog2, cat] after the next line animals.push(cat1)

与 T 是协变的,这意味着

Sequence[T]
Sequence[Dogs] 的子类型。这是允许的,因为 Sequence[Animals]
 没有“插入”方法,因此您永远不会意外地将 
Sequence
 偷偷放入 
Cat
 中:
Sequence[Dog]


© www.soinside.com 2019 - 2024. All rights reserved.