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

Stiivi picture Stiivi  路  3Comments

edwardcwang picture edwardcwang  路  3Comments

ambv picture ambv  路  3Comments

squarewave24 picture squarewave24  路  3Comments

JelleZijlstra picture JelleZijlstra  路  4Comments