PEP 647's invariant rules

I’ve been diving into PEPs 724 – Stricter Type Guards and 647 – User-Defined Type Guards and I don’t understand this claim made in the latter:

For instance, the is_str_list example above would be considered invalid because List[str] is not a subtype of List[object] because of invariance rules.

Apparently Ilya Kamen (is he here?) didn’t either in issue 996 which is part of the discussion that led to PEP 724:

Re-reading the PEP, I still can’t understand because List[str] is not a subtype of List[object] because of invariance rules. I thought str is a subtype of object + List is covariant.

Which is my understanding as well.

So what am I missing here?

List is invariant, not covariant. Covariance, Contravariance, and Invariance — The Ultimate Python Guide | by Paweł Święcki | Daftcode Blog

1 Like

Ok I think I understood right after I posted but I’ll leave it here for future readers: the issue is as usual that I always mess up type variance. For a simple example, this is something that you can you can do with a List[object] but can’t with a List[str]:

lst_o: list[object] = ["spam", "ham"]
lst_o.append.(object())  # This is correct

lst_s: list[str] = ["spam", "ham"]
lst_s.append(object())  # This is not correct

Since there is something that a List[object] can do but a List[str] can’t, according to Liskov’s substitution principle, List[str] is not a subtype of List[object].

1 Like