Search code examples
pythoninheritancepython-typingmypy

Why is a property on a subclass, that returns a type consistent with the same attribute on the superclass disallowed


class Foo:
    bar: str

class Bat(Foo):
    @property
    def bar(self) -> str:
        ...

Given the above code, my typechecker (mypy) raises the following complaint:

error: Signature of "bar" incompatible with supertype "Foo"  [override]

This surprises me given that an instance of Foo or Bat will behave the same from the perspective of a caller accessing the bar attribute/property. What is the issue the typechecker is preventing by rejecting this code?


Solution

  • Expanding on the comments to the OP:

    Older versions of Mypy had some sort of issue/bug somehow tangentially related to this that led to some discussions on the project's GitHub: Mypy disallows overriding an attribute with a property and that should have be fixed on versions >=v0.990

    There's also a discussion which feels much closer to the current's OP exposition: overriding variable with property: error Signature incompatible with supertype

    In this second case, what happens is that...

    class Foo:
        bar: str
    

    ...tells Mypy that .bar will be a writable attribute, whereas just declaring the @property in the child class Bat...

    class Bat(Foo):
        @property
        def bar(self) -> str:
    

    ... would make the attribute read-only. The most straightforward fix, in this case, might be creating a setter for .bar.

    The following code:

    class Foo:
        bar: str
    
    
    class Bat(Foo):
        @property
        def bar(self) -> str:
            return "something"
    
        @bar.setter
        def bar(self, value: str):
            # ... actual setter code probably
            # for self._bar or something like that
            pass
    

    Produces:

    Success: no issues found in 1 source file