Question

What is an invariant list in MyPy?

Answer and Explanation

In MyPy, an invariant list refers to how type checking is handled with lists and their contained types. Specifically, it means that a list of a specific type is not considered a subtype of a list of a more general type, even if the contained type is a subtype of the more general type.

Let's break this down with an example:

Suppose you have two classes, Animal and Dog, where Dog is a subclass of Animal:

class Animal:
  pass

class Dog(Animal):
  pass

In a type system that supports covariance, you might expect that a List[Dog] would be a subtype of List[Animal], because a Dog is a subtype of Animal. However, in MyPy, lists are invariant. This means that List[Dog] is not considered a subtype of List[Animal], nor is List[Animal] a subtype of List[Dog]. They are treated as distinct types.

Here's why this is important:

Type Safety: If lists were covariant, you could potentially add an Animal that is not a Dog to a List[Dog], which would violate type safety. For example:

from typing import List

def add_animal(animals: List[Animal], animal: Animal) -> None:
  animals.append(animal)

dogs: List[Dog] = [Dog(), Dog()]

# If List was covariant, this would be allowed, but it's not:
# add_animal(dogs, Animal()) # This would cause a type error in MyPy

# This is correct:
add_animal(dogs, Dog())

In the above example, if List were covariant, you could pass a List[Dog] to a function expecting a List[Animal]. The function could then add a generic Animal to the list, which would not be a Dog, leading to runtime errors if you later tried to treat all elements of the list as Dog objects. MyPy prevents this by enforcing invariance.

Implications:

- You cannot directly pass a List[Dog] where a List[Animal] is expected, or vice versa.

- You need to be explicit about the types of lists you are using, especially when dealing with inheritance.

- If you need to work with a list of a more general type, you might need to create a new list or use a different data structure.

In summary, an invariant list in MyPy ensures type safety by preventing you from treating a list of a specific type as a list of a more general type, even if the contained types have an inheritance relationship. This helps catch potential type errors at compile time rather than at runtime.

More questions