Invariance vs covariance

Most mutable generic collections are invariant, and mypy considers alluser-defined generic classes invariant by default(see Variance of generic types for motivation). This could lead to someunexpected errors when combined with type inference. For example:

  1. class A: ...
  2. class B(A): ...
  3.  
  4. lst = [A(), A()] # Inferred type is List[A]
  5. new_lst = [B(), B()] # inferred type is List[B]
  6. lst = new_lst # mypy will complain about this, because List is invariant

Possible strategies in such situations are:

  • Use an explicit type annotation:
  1. new_lst: List[A] = [B(), B()]
  2. lst = new_lst # OK
  • Make a copy of the right hand side:
  1. lst = list(new_lst) # Also OK
  • Use immutable collections as annotations whenever possible:
  1. def f_bad(x: List[A]) -> A:
  2. return x[0]
  3. f_bad(new_lst) # Fails
  4.  
  5. def f_good(x: Sequence[A]) -> A:
  6. return x[0]
  7. f_good(new_lst) # OK