Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

mypy trouble with inheritance of objects in lists

Python 3.6.5 and mypy 0.600

I wrote the code:

from typing import List


class Animal():
    pass


class Dog(Animal):
    def __init__(self) -> None:
        super()

    def bark(self) -> None:
        pass


class Cat(Animal):
    def __init__(self) -> None:
        super()

    def meow(self) -> None:
        pass


arr1: List[Dog] = [Dog(), Dog()]
arr2: List[Animal] = [Dog(), Dog()]

# error: Incompatible types in assignment (expression has type "List[Dog]", variable has type "List[Animal]")
arr3: List[Animal] = arr1

I don't understand, why I have an error 'Incompatible types in assignment ' with a variable 'arr3'. Dog is a class which inherits from a Animal. For example, I don't have an error with variable 'arr2'.

like image 667
user3517175 Avatar asked May 12 '18 11:05

user3517175


People also ask

Why is mypy so slow?

Mypy runs are slow If your mypy runs feel slow, you should probably use the mypy daemon, which can speed up incremental mypy runtimes by a factor of 10 or more. Remote caching can make cold mypy runs several times faster.

How do I ignore MYPY errors?

You can use a special comment # type: ignore[code, ...] to only ignore errors with a specific error code (or codes) on a particular line. This can be used even if you have not configured mypy to show error codes. Currently it's only possible to disable arbitrary error codes on individual lines using this comment.

Does Python support multiple inheritance diamond problem?

In Python as all classes inherit from object, potentially multiple copies of object are inherited whenever multiple inheritance is used. That is, the diamond problem occurs even in the simplest of multiple inheritance.


1 Answers

Imagine that this would be possible:

arr3: List[Animal] = arr1

Now you think you have list of animals, but this is actually a list of dogs (note that arr3 is not a copy of arr1, they are the same list).

And because you think this is the list of animals you can add a Cat to it.

However, because this is actually list of dogs, you cannot add a Cat to it. Otherwise you will fail on AttributeError after trying to use dog-specific attribute.

More generally, list is invariant - List[Animal] cannot be assigned to List[Dog] (because it can already contain cats) and List[Dog] cannot be assigned to List[Animal] (because you can add cat later)


This might not be obvious in Python, but you can make simple test:

arr3: List[Animal] = arr1 
arr3.append(Cat())
for dog in arr1:
    print(dog.bark())

Mypy does not allow this because this assignment might break your code logic

like image 98
awesoon Avatar answered Nov 15 '22 23:11

awesoon