Python中Sequence协变特性下子类列表赋值及append方法类型错误的问题问询
各位大佬,最近在处理Python类型注解的时候遇到了一个绕人的问题,想跟大家请教下!
先看第一个完全正常的场景:我定义了父类Foo和两个子类Child1、Child2,把子类实例放到声明为list[Foo]的列表里,不管是初始化还是后续append其他子类,都没有类型错误:
class Foo(): pass class Child1(Foo): pass class Child2(Foo): pass my_list: list[Foo] = [Child1()] my_list.append(Child2())
但接下来的情况就出问题了:我写了个返回list[Child1]的函数,把它的返回值赋值给list[Foo]类型的变量时,类型检查器直接报错,说list[Child1]不能赋值给list[Foo]——这点我能理解,毕竟list的类型参数是**不变(invariant)**的,要是允许这么做,后续往列表里加Child2会破坏类型安全。
然后我按照提示换成了支持**协变(covariant)**的Sequence,赋值这一步确实不报错了:
def list_of_child1() -> list[Child1]: return [Child1(), Child1()] my_list3: Sequence[Foo] = list_of_child1()
可奇怪的事情来了!当我尝试给my_list3 append一个Child2实例时,又报错了:提示Child2不能赋值给Child1类型的参数。明明我声明的是Sequence[Foo],怎么类型检查器好像把它当成list[Child1]来处理了?
更让我摸不着头脑的是下面这个场景:我先把my_list4声明为Sequence[Foo]并初始化为空列表,用extend加入list_of_child1()的内容后,再appendChild2就完全没问题:
my_list4: Sequence[Foo] = [] my_list4.extend(list_of_child1()) my_list4.append(Child2())
有没有大佬能拆解下这中间的逻辑?为什么同样是Sequence[Foo],直接赋值子类列表后就不能append其他子类,而先初始化空列表再extend就可以?这跟Sequence的协变特性到底是怎么互动的?
内容来源于stack exchange

