预期类型 'List[A]'(匹配泛型类型 'List[_T]'),在正确键入的列表中得到 'List[B]' 而不是

Expected type 'List[A]' (matched generic type 'List[_T]'), got 'List[B]' instead on correctly typed lists

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 是不变的,这意味着 List[X] 而不是 替代 List[Y] 除非 XY 完全相同平等的。同样,A <: Base 并不意味着 List[A] <: List[Base] 并且 B.

也是如此

PEP 484: Covariance and contravriance

[...]
By default generic types are considered invariant in all type variables, which means that values for variables annotated with types like List[Employee] must exactly match the type annotation -- no subclasses or superclasses of the type parameter (in this example Employee) are allowed.

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


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

from typing import Sequence

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

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

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

Pre-emptively 扩大操作数的类型可能是不可取的或不可能的。或者,可以在使用地点 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 有效地禁用了对转换值的类型检查。仅在已知正确的情况下使用它。