如何为列表中的子类正确添加类型提示?
问题分析与解决方案
为什么会报错?
Python类型系统中,list是不变类型——即便B是A的子类,list[Optional[B]]也不属于list[Optional[A]]的子类型。这和单个实例赋值(如bb: A = B())不同:单个实例的赋值是安全的,因为你无法通过bb变量往里面混入其他子类实例;但如果允许把list[B]赋值给list[A],后续你可以通过my_dict["b"].append(C()),导致原本只能容纳B/None的列表混入C实例,破坏类型安全,因此mypy会禁止这种赋值。
简洁解决方案
方案1:使用协变的Sequence类型
如果你的字典中的列表不需要被修改(只读场景),可以将字典的类型标注改为dict[str, Sequence[Optional[A]]]。Sequence是协变类型,list[Optional[B]]可以兼容Sequence[Optional[A]]:
from typing import Optional, Sequence class A: ... class B(A): ... class C(A): ... my_dict: dict[str, Sequence[Optional[A]]] = {"b": [], "c": []} b: list[Optional[B]] = [B()] c: list[Optional[C]] = [C()] my_dict["b"] = b my_dict["c"] = c
方案2:用cast强制类型转换(适合可变列表场景)
如果必须保持列表的可变性,可以用typing.cast告诉mypy你确认该赋值是安全的(需自行保证后续不会往列表中混入不符合类型的元素):
from typing import Optional, cast class A: ... class B(A): ... class C(A): ... my_dict: dict[str, list[Optional[A]]] = {"b": [], "c": []} b: list[Optional[B]] = [B()] c: list[Optional[C]] = [C()] my_dict["b"] = cast(list[Optional[A]], b) my_dict["c"] = cast(list[Optional[A]], c)
方案3:精确标注字典值的联合类型(子类较少时适用)
如果子类数量不多,可以直接将字典的类型标注为包含所有子类列表类型的联合:
from typing import Optional, Union class A: ... class B(A): ... class C(A): ... my_dict: dict[str, Union[list[Optional[B]], list[Optional[C]]]] = {"b": [], "c": []} b: list[Optional[B]] = [B()] c: list[Optional[C]] = [C()] my_dict["b"] = b my_dict["c"] = c
内容的提问来源于stack exchange,提问作者Ken Jiiii
相关产品推荐
相关产品推荐

