预期类型"列表[A]"(匹配的泛型类型"列表[_T]"),在正确键入的列表中获得"列表[B]"


from typing import List

class Base(object):
pass

class A(Base):
pass

class B(Base):
pass

a: List[A] = []
b: List[B] = []
c: List[Base] = a + b

我在b上得到Expected type 'List[A]' (matched generic type 'List[_T]'), got 'List[B]' instead

我该如何获得正确的警告,因为显然这些类型都很好。

这些类型是不好的。List是不变的,这意味着除非XY完全相等,否则List[X]而不是List[Y]的替代品。类似地,A <: Base并不意味着List[A] <: List[Base],对于B也是如此。

PEP484:协方差和逆变

[…]
默认情况下,泛型类型在所有类型变量中都是不变的,这意味着用List[Employee]等类型注释的变量的值必须与类型注释完全匹配——不允许类型参数的子类或超类(在本例中为Employee(。

虽然可以重新解释此操作的类型,但这并不明确。保守类型检查器将拒绝该操作,而不是猜测。


List这样的可变容器是不变的,因为元素既可以被插入到(逆变(中,也可以从(协变(列表中取出。如果不需要可变性,那么使用不可变序列可以提供有效的类型注释:

from typing import Sequence
a: Sequence[A] = []
b: Sequence[B] = []
c: Sequence[Base] = [*a, *b]

如果需要可变性,可以显式枚举要在List中找到的所有类型。即使每个单独的列表实际上只包含一种类型,这也会先发制人地扩大列表中预期的元素。

a: List[Union[A, B]] = []
b: List[Union[A, B]] = []
c: List[Union[A, B]] = a + b

先发制人地扩大操作数的类型可能是不可取的或不可能的。或者,可以在使用现场cast

a: List[A] = []
b: List[B] = []
c: List[Union[A, B]] = cast(List[Union[A, B]], a) + cast(List[Union[A, B]], a)

请注意,cast有效地禁用了cast'ed值的类型检查。仅在已知正确的情况下使用。

最新更新