Mypy: List[subclass] is incompatible with List[superclass]

Created on 10 Mar 2017  路  3Comments  路  Source: python/mypy

When a function that is accepting a list of a base class (for example class Base) is passed and argument which is a list of subclass instances of the base class (for example Thing(Base)) mypy complains about incompatible type: Error: Argument 1 to "function" has incompatible type List[Thing]; expected List[Base].

Wrapping the argument with a cast to a list of the base class passes.

Code example:

from typing import List, cast

class Base:
    pass

class Thing(Base):
    pass

def function(arg: List[Base]) -> None:
    pass

things:List[Thing] = [Thing()]

# Error: Argument 1 to "function" has incompatible type List[Thing]; expected List[Base]
function(things)

# Passes
function(cast(List[Base], things))

Most helpful comment

This is expected behavior and documented at http://mypy.readthedocs.io/en/latest/generics.html#variance-of-generic-types. Your example would fail with code like this:

things: List[Thing] = []

def function(arg: List[Base]) -> None:
    arg.append(Base())

function(things)

for thing in things:
    assert isinstance(thing, Thing)  # fails at runtime, but type checker detects no errors

If your function doesn't actually modify the list, you can get around this error by typing the argument as Sequence[Base] or even Iterable[Base] instead.

All 3 comments

This is as designed, please read up on Liskov.

You can often use Sequence[x] instead of List[x] to get code like your example working. This works because Sequence is covariant and doesn't let you set items in the list, unlike List[x] which is invariant and allows the mutation of the list.

This is expected behavior and documented at http://mypy.readthedocs.io/en/latest/generics.html#variance-of-generic-types. Your example would fail with code like this:

things: List[Thing] = []

def function(arg: List[Base]) -> None:
    arg.append(Base())

function(things)

for thing in things:
    assert isinstance(thing, Thing)  # fails at runtime, but type checker detects no errors

If your function doesn't actually modify the list, you can get around this error by typing the argument as Sequence[Base] or even Iterable[Base] instead.

Was this page helpful?
0 / 5 - 0 ratings