0

I have an abstract base class of which I'm only showing a small portion here, to illustrate my issue.

The abstract base class A below has a property onemore that uses the instance attribute val. Below it are subclasses B and C, which provide this attribute in distinct (but both valid) ways.

So far, so good:

from abc import ABC, abstractmethod

class A(ABC):
    @property
    def onemore(self) -> int:
        return self.val + 1


class B(A):
    def __init__(self, value):
        self._val = value

    val = property(lambda self: self._val)


class C(A):
    def __init__(self, value):
        self.val = value


b = B(32)
b.onemore  # 33
c = C(54)
c.onemore  # 55

Now here is my question: is there a way to define A in such a way, that it's more clear that the subclasses need to implement val? As it's defined above, this is hard to miss, esp. if A has many more methods.

I tried this:

class A(ABC):
    @property
    @abstractmethod
    def val(self) -> int:
        ...

    @property
    def onemore(self) -> int:
        return self.val + 1

This definition is too strict, though: I don't want to demand that the subclasses implement val as a property, I just want to require them to have it as a (readable) attribute. In other words, I want C to be a valid subclass, which is not the case here: this definition does not work with how C provides self.val. (TypeError: Can't instantiate abstract class C with abstract method val).

Any ideas?

PS I have seen this question, which is similar, but doesn't solve the TypeError I'm getting.

ElRudi
  • 2,122
  • 2
  • 18
  • 33
  • I think `@abstractmethod` is the only canonical approach that comes to mind unfortunately – Cory Kramer Dec 09 '21 at 11:41
  • You can't simultaneously benefit from the strictness imposed by `ABC` and `abstractmethod` while also demanding more flexibility than those tools can provide. There is nothing you won't be able to do by simply always having `val` be a property. Bending over backwards to avoid using `property` would result in poor design for the sole purpose of avoiding having to write `def val` a bit more than you'd like to. – ticster Dec 10 '21 at 10:54
  • I see, thanks for that comment. I was trying to provide flexibility for devs who are implementing the subclasses and also to avoid breaking compatibility with existing implementations. But I guess that's not possible then. – ElRudi Dec 11 '21 at 11:30

0 Answers0