3

What's the best, most Pythonic, way to deal with abstract properties in Python? If I want to implement a base class which has a mixture of abstract properties, and concrete methods, I can do so similar to the following.

class BaseClass(object):
    __metaclass__ = ABCMeta

    @abstractmethod
    def property1(self):
        pass

    @abstractmethod
    def property2(self):
        pass

    @abstractmethod
    def property3(self):
        pass

    @abstractmethod
    def abstract_method(self):
        pass

    def concrete_method(self):
        return self.property1 + self.property2

However, when I then go to implement the inheriting class I need to implement each of those properties as getter method for a private property.

class Klass(BaseClass):
    def __init__(self, property1, property2, property3):
        self.__property1 = property1
        self.__property2 = property2
        self.__property3 = property3

    @property
    def property1(self):
        return self.__property1

    @property
    def property2(self):
        return self.__property2

    @property
    def property3(self):
        return self.__property3

Which seems both unnecessarily verbose, and makes the code more obscure than it needs to be.

I don't love the idea of implementing things concretely and raising a NotImplementedErrorif the inheriting class doesn't implement it's own version.

Is there a better way to do this?

1
  • I know this comment does not change anything now, since this has a correct and accepted answer, but just for correctness, aren't you missing the @property decorator from property1, etc. in BaseClass? The concrete_method implementation suggests you really want to use these as attributes rather than method calls. But back in 2016, you probably could not stack/nest decorators...@abstractproperty was invented for that Commented Feb 22, 2024 at 17:47

1 Answer 1

3

You are not required to implement properties as properties. All you need is for the name to exist on the class. So the following, using regular attributes, would work:

class Klass(BaseClass):
    property1 = None
    property2 = None
    property3 = None

    def __init__(self, property1, property2, property3):
        self.property1 = property1
        self.property2 = property2
        self.property3 = property3

    def abstract_method(self):
        # implementation for the abstract method

Note that there is a abstractproperty decorator that'd better document that you want to use those names as simple values, not methods to call:

class BaseClass(object):
    __metaclass__ = ABCMeta

    @abstractproperty
    def property1(self):
        pass

    @abstractproperty
    def property2(self):
        pass

    @abstractproperty
    def property3(self):
        pass

    @abstractmethod    
    def abstract_method(self):
        pass

    def concrete_method(self):
        return self.property1 + self.property2
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks. I knew that the abstractproperty decorator existed, but it didn't make much sense to me to use it. This is a lot more readable.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.