3

The following code gives me a type mismatch error under strict typeschecking in Python.

class DataClass1(ABC):
    @abstractmethod
    def to_int(self) -> int:
        return 1

class DataClass2(DataClass1):
    def __init__(self, value: int):
        self.value = value
    
    def to_int(self) -> int:
        return self.value 

class WidgetClass(ABC):
    @abstractmethod
    def calculate(self, data: DataClass1) -> DataClass1:
        pass

class WidgetClassImp(WidgetClass):
    def calculate(self, data: DataClass2):
        return data

The WidgetClassImp which receives a subclass of DataClass1 as argument causes the typemismatch to occur. This is surprising as DataClass2 is a subclass of DataClass1 and implements the DataClass1 interface.

Am I doing something wrong?

2 Answers2

2

This can be solved by using annotation data: type[DataClass1].

The modified code will be as follows:

from typing import type

class DataClass1(ABC):
    @abstractmethod
    def to_int(self) -> int:
        return 1

class DataClass2(DataClass1):
    def __init__(self, value: int):
        self.value = value
    
    def to_int(self) -> int:
        return self.value 

class WidgetClass(ABC):
    @abstractmethod
    def calculate(self, data: DataClass1) -> DataClass1:
        pass

class WidgetClassImp(WidgetClass):
    def calculate(self, data: type[DataClass1]):
        return data

The reason the above code works is that in the first case the type system assumes an instance of DataClass1. As DataClass2 is not an instance it raises a warning.

When we annotate it with type[DataClass1] it says to the typechecker to look for types of DataClass1. As DataClass2 is a subtype of DataClass1 no error will be raised.

1

A subclass is not the parent class. Therefore declaring WidgetClassImp needing a Dataclass2 changes the funcion signature to its parent therefore typemismatch. You need to also declare Dataclass1 as Parameter and inside the logic either cast to Dataclass2 or only use dataclass1 members.

4lexKidd
  • 158
  • 1
  • 1
  • 9
  • 1
    An instance of a subclass is in fact also an instance of the parent class. Especially regarding python typing. PEP484 states "Expressions whose type is a subtype of a specific argument type are also accepted for that argument." https://peps.python.org/pep-0484/#type-definition-syntax – toraman Apr 21 '23 at 21:41