Mypy: Overridden classmethod factory infers wrong type from super()

Created on 28 Sep 2017  路  3Comments  路  Source: python/mypy

Calling a superclass' factory method via super() infers the type of the superclass, rather than the type of the subclass.

# tmp.py

class A:
    @classmethod
    def new(cls) -> 'A':
        return cls()


class B(A):

    def print_foo(self):
        print('foo')

    @classmethod
    def new(cls) -> 'B':
        inst = super().new()
        inst.print_foo()
        return inst


assert isinstance(B.new(), B)
tmp.py:16: error: "A" has no attribute "print_foo"
tmp.py:17: error: Incompatible return value type (got "A", expected "B")

If attempting to specify the type of inst using inst = super().new() # type: 'B', mypy generates the following error:

tmp.py:15: error: Incompatible types in assignment (expression has type "A", variable has type "B")

Removing the type hint from the A.new gets rid of the errors.

PyLint also infers this type incorrectly, regardless of type hinting. See PyCQA/pylint#981 for details.

Most helpful comment

Also, docs for this feature: http://mypy.readthedocs.io/en/latest/generics.html#generic-methods-and-generic-self

All 3 comments

You should use a "self-type" in the signature of the new() method:

T = TypeVar('T')
class A:
    @classmethod
    def new(cls: Type[T]) -> T: ...

But how mypy would know that it is more precise if you annotated the return type of A.new as A? You should do it like this:

TA = TypeVar('TA', bound='A')
TB = TypeVar('TB', bound='B')

class A:
    @classmethod
    def new(cls: Type[TA]) -> TA:
        return cls()


class B(A):

    def print_foo(self):
        print('foo')

    @classmethod
    def new(cls: Type[TB]) -> TB:
        inst = super().new()
        inst.print_foo()
        return inst

Also, docs for this feature: http://mypy.readthedocs.io/en/latest/generics.html#generic-methods-and-generic-self

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jstasiak picture jstasiak  路  3Comments

kissge picture kissge  路  3Comments

JelleZijlstra picture JelleZijlstra  路  4Comments

PeterJCLaw picture PeterJCLaw  路  3Comments

JukkaL picture JukkaL  路  4Comments