【问题标题】:Expected type 'List[A]' (matched generic type 'List[_T]'), got 'List[B]' instead on correctly typed lists预期类型 'List[A]'(匹配的泛型类型 'List[_T]'),得到了 'List[B]' 而不是正确键入的列表
【发布时间】:2022-01-19 18:40:52
【问题描述】:
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

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

【问题讨论】:

标签: python python-typing


【解决方案1】:

这些类型不好。 List 是不变的,这意味着 List[X] 不是替代 List[Y],除非 XY 完全相等。同样,A <: Base 并不暗示 List[A] <: List[Base]B 也是如此。

PEP 484: Covariance and contravriance

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

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


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

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 有效地禁用了对强制转换值的类型检查。仅在已知正确的情况下使用它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-09-09
    • 2018-04-30
    • 2019-12-27
    • 2021-02-07
    • 2019-06-10
    • 1970-01-01
    • 1970-01-01
    • 2021-06-24
    相关资源
    最近更新 更多