Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Use list of derived class as list of base class in Python

I have a function which takes a list of a base class as argument, and I have a variable which is a list of a derived class. Using this variable as the argument gives mypy error: Argument 1 to "do_stuff" has incompatible type "List[DerivedClass]"; expected "List[BaseClass]".

class BaseClass(TypedDict):
    base_field: str

class DerivedClass(BaseClass):
    derived_field: str

def do_stuff(data: List[BaseClass]) -> None:
    pass

foo: List[DerivedClass] = [{'base_field': 'foo', 'derived_field': 'bar'}]

do_stuff(foo)

If the argument and variable are instead BaseClass and DerivedClass respectively, i.e. not lists, it understands that the variable can be casted implicitly to the base class. But for lists it doesn’t work. How can I solve this, preferably other than #type: ignore.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

It depends on what exactly do_stuff is doing, but nine times out of ten the best solution is to use Sequence instead of List:

from typing import Sequence

def do_stuff(data: Sequence[BaseClass]) -> None:
    pass

The reason you can’t use List[BaseClass] here is that do_stuff would be allowed to add BaseClass instances to data, which would in turn break foo in the caller. Sequence doesn’t imply mutability, so do_stuff is not allowed (static-typing-wise) to modify a Sequence parameter, which prevents that issue. (Put differently, Sequence is covariant and List is invariant. Most mutable generics are invariant because of exactly this issue.)

If do_stuff does need to mutate data, you’ll need to rethink the typing — should it be allowed to add a BaseClass to it? If not, maybe do_stuff should take a List[DerivedClass]. If so, you need to declare foo as a List[BaseClass] to account for that possibility.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading