randomness2077
randomness2077

Reputation: 1139

Python TypeHint: What Return Type to use for the factory methods?

Here is my code snippet. I wonder what return type to use for the create classmethod of both factory classes. I would like to avoid using Union[Model1, Model2] if it's possible.

T = typing.TypeVar("T", bound="BaseModel")


@dataclass
class BaseModel(object):
    pass


@dataclass
class Model1(BaseModel):
    pass


@dataclass
class Model2(BaseModel):
    pass


class ModelFactory(ABC):
    @classmethod
    @abstractmethod
    def create(cls) -> T:
        pass


class Model1Factory(ModelFactory):
    @classmethod
    def create(cls) -> T:
        return Model1()


class Model2Factory(ModelFactory):
    @classmethod
    def create(cls) -> T:
        return Model2()

m1factory = Model1Factory()
m1 = m1factory.create()

The error I am getting from mypy:

type_hint.child_class_return_self.2.py:32: error: Incompatible return value type (got "Model1", expected "T")
type_hint.child_class_return_self.2.py:37: error: Incompatible return value type (got "Model2", expected "T")
type_hint.child_class_return_self.2.py:41: error: Need type annotation for 'm1'

Upvotes: 0

Views: 1434

Answers (2)

amsh
amsh

Reputation: 3387

According to mypy cheat sheet you should go for Union[Model1, Model2], but if it's something you want to avoid, the next best candidate is Any type.

Upvotes: 0

star99ers
star99ers

Reputation: 76

I think you just need to incorporate Generic into the equation so that mypy can accept different return types:

from abc import ABC
from typing import Generic, TypeVar


T = typing.TypeVar("T", bound="BaseModel")


@dataclass
class BaseModel(object):
    pass


@dataclass
class Model1(BaseModel):
    pass


@dataclass
class Model2(BaseModel):
    pass


class ModelFactory(Generic[T], ABC):
    @classmethod
    @abstractmethod
    def create(cls) -> T:
        pass


class Model1Factory(ModelFactory[Model1]):
    @classmethod
    def create(cls) -> Model1:
        return Model1()


class Model2Factory(ModelFactory[Model2]):
    @classmethod
    def create(cls) -> Model2:
        return Model2()


m1factory = Model1Factory()
m1 = m1factory.create()

Upvotes: 2

Related Questions