Search code examples
pythonpropertiesmypypython-typingabc

python/mypy: how to declare ABC using value implemented both as property and attribute


I have an abstract baseclass which uses a value whose implementation in different concrete classes can be either an attribute or a property:

from abc import ABC, abstractmethod


class Base(ABC):

    n: int

    
    def foo(self):
        ...
        a = ... + self.n

    @abstractmethod
    def bar(self):
        ...

class X(Base):
    def __init__(self, n: int):
      self.n = n

    def bar(self):
        ...

class Y(Base):

    @property
    def n(self) -> int:
        ...

    def bar(self):
        ...

The above code (outline, appropriately filled out), works at runtime, but mypy complains about the property in Y:

error: Signature of "n" incompatible with supertype "Base"

However, I can't remove the n: int because of foo, and I also can't put in an abstract property, because this breaks X. How should I declare the base class to make mypy happy with it?


Solution

  • Y can't be less flexible than Base and be a subclass, so you're likely going to need to make n an abstract property on Base then add a setter to X. It's not pretty, but it works (I think, I haven't checked)

    class X(Base):
        def __init__(self, n: int):
            self._n = n
    
        @property
        def n(self) -> int:
            return self._n
    
        @n.setter
        def n(self, n: int) -> None:
            self._n = n
    
        ...