1

How can I implement a custom constructor (class method) that is inheritable in python?

The following minimized example might give an idea:

from dataclasses import dataclass
from typing import Type, TypeVar

T = TypeVar("T")


@dataclass
class Parent:
    something: int = 2

    @classmethod
    def from_float(cls: Type[T], something_as_float: float) -> T:
        return Type[T](something=int(something_as_float))


@dataclass
class Child(Parent):
    """ Should also be constructible via from_float
    """


assert isinstance(Parent.from_float(1.0), Parent)
assert isinstance(Child.from_float(1.0), Child)

mypy does not like the constructor I call when returning from from_float. I don't know how to refer to class (Parent or Child) from the class method.

Alex Waygood
  • 6,304
  • 3
  • 24
  • 46
Andrew Wagner
  • 22,677
  • 21
  • 86
  • 100

1 Answers1

3

Pass the bound argument to TypeVar to specify that the type is a subclass of Parent. This lets mypy know that the type has the something attribute

When you create the instance use cls not Type[T]

from dataclasses import dataclass
from typing import Type, TypeVar

T = TypeVar("T", bound='Parent')


@dataclass
class Parent:
    something: int = 2

    @classmethod
    def from_float(cls: Type[T], something_as_float: float) -> T:
        return cls(something=int(something_as_float))


@dataclass
class Child(Parent):
    pass


assert isinstance(Parent.from_float(1.0), Parent)
assert isinstance(Child.from_float(1.0), Child)
Iain Shelvington
  • 31,030
  • 3
  • 31
  • 50
  • Whoooo that did it. Thanks! I can confirm locally that it runs with out asserting, and also passes mypy! – Andrew Wagner Sep 28 '21 at 13:20
  • You can't refer a class within its definition... and escaping as cls: "Parent" and -> "Parent" didn't help either. I hit "The erased type of self "minimized_typing_puzzle.Parent" is not a supertype of its class "Type[minimized_typing_puzzle.Parent]"" and then error: "Parent" not callable. Iain's solution works, but feel free to keep the thread going if you enjoy typing puzzles. Thanks! – Andrew Wagner Sep 28 '21 at 13:28