Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python Abstract class with concrete methods

I'm wondering if in python (3) an abstract class can have concrete methods.
Although this seems to work I'm not sure this is the proper way to do this in python:

from abc import ABCMeta, abstractclassmethod, abstractmethod 

class MyBaseClass:
    __metaclass__ = ABCMeta

    @property
    @abstractmethod
    def foo_prop(self):
        """Define me"""
        pass

    @abstractclassmethod
    def get_something(cls, param1, param2, param3):
        """This is a class method, override it with @classmethod """
        pass

    @classmethod
    def get(cls, param1, param2):
        """Concrete method calling an abstract class method and an abstract property""" 
        if param1 < cls.foo_prop:
            raise Exception()
        param3 = param1 + 42
        item = cls.get_something(param1, param2, param3)
        return item


class MyConcreteClassA(MyBaseClass):
    """Implementation """

    foo_prop = 99

    @classmethod
    def get_something(cls, param1, param2, param3):
        return cls.foo_prop + param1 + param2 + param3


class MyConcreteClassB(MyBaseClass):
    """Implementation """

    foo_prop = 255

    @classmethod
    def get_something(cls, param1, param2, param3):
        return cls.foo_prop - param1 - param2 - param3

In the example the abstract class MyBaseClass has:

  • an abstract property foo_prop that will be defined in the subclasses
    • the only way I could find to declare this was to create an abstract "property method"
  • an abstract class method get_something that will be implemented in the subclasses
  • a concrete method get that in turns uses the (not yet defined) abstract method and property mentioned above.

Questions:

  1. Is there a better way to define an abstract property? Would it make more sense to define a concrete property in MyBaseClass set to None and just redefine it in the subclasses?

  2. Can I mix abstract and concrete methods in an abstract class as shown in the example?

  3. If yes, does it always makes sense to declare the class abstract or can a concrete class have abstract methods (in this case it should never be instantiated directly anyway).

Thanks

like image 347
Leonardo Avatar asked Nov 28 '17 15:11

Leonardo


1 Answers

  1. According to the docs (text in brackets and code formatting mine):

    [@abstractproperty is] Deprecated since version 3.3: It is now possible to use property, property.getter(), property.setter() and property.deleter() with abstractmethod(), making this decorator redundant.

    so I think you're doing it right.

  2. You can do this, or at least in my experience it has not been an issue. Maybe somebody else can offer other advice, but that advice will probably take the form of "inheritance is bad". Although I don't see anything explicitly about it in the docs, this section shows an example wherein an abstract method, concrete method, and class method are all defined within an ABC.

  3. I believe you still have to declare the class abstract in order to use @abstractmethod and similar decorators. By setting the metaclass as ABC, the class cannot be instantiated until all abstract methods are defined, which sounds like the behavior that you want, so I think you need to declare it abstract unless you just want to rely on documentation to enforce the "you shall not instantiate" rule on this class. As an aside, you can declare your abstract class with:

    from abc import ABC
    class MyBaseClass(ABC):
        # ...
    

    inheriting from abc instead of manually setting the metaclass. I think this construction is preferred.

like image 98
Engineero Avatar answered Oct 01 '22 23:10

Engineero