I’ve seen code that declares abstract methods that actually have a non-trivial body.
What is the point of this since you have to implement in any concrete class anyway?
Is it just to allow you to do something like this?
def method_a(self):
super(self).method_a()
CodePudding user response:
I've used this before in cases where it was possible to have the concrete implementation, but I wanted to force subclass implementers to consider if that implementation is appropriate for them.
One specific example: I was implementing an abstract base class with an abstract factory method so subclasses can define their own __init__
function but have a common interface to create them. It was something like.
class Foo:
def __init__(self, a, b, c):
self.a = a
self.b = b
self.c = c
@classmethod
@abstractmethod
def from_args(cls, a, b, c) -> "Foo":
return cls(a, b, c)
Subclasses usually only need a subset of the arguments. When testing, it's cumbersome to access the framework which actually uses this factory method, so it's likely someone will forget to implement the from_args
factory function since it wouldn't come up in their usual testing. Making it an abstractmethod
would make it impossible to initialize the class without first implementing it, and will definitely come up during normal testing.
CodePudding user response:
Abstract classes are classes that contain one or more abstract methods. An abstract method is a method that is declared but contains no implementation. Abstract classes cannot be instantiated, and require subclasses to provide implementations for the abstract methods.
You can see this in the following examples:
class AbstractClass:
def do_something(self):
pass
class B(AbstractClass):
pass
a = AbstractClass()
b = B()
If we start this program, we see that this is not an abstract class, because:
we can instantiate an instance from we are not required to implement do_something in the class definition of B Our example implemented a case of simple inheritance which has nothing to do with an abstract class. In fact, Python on its own doesn't provide abstract classes. Yet, Python comes with a module that provides the infrastructure for defining Abstract Base Classes (ABCs). This module is called - for obvious reasons - abc.
The following Python code uses the abc module and defines an abstract base class:
from abc import ABC, abstractmethod
class AbstractClassExample(ABC):
def __init__(self, value):
self.value = value
super().__init__()
@abstractmethod
def do_something(self):
pass
We will define now a subclass using the previously defined abstract class. You will notice that we haven't implemented the do_something method, even though we are required to implement it, because this method is decorated as an abstract method with the decorator abstractmethod
. We get an exception that DoAdd42 can't be instantiated:
class DoAdd42(AbstractClassExample):
pass
x = DoAdd42(4)
OUTPUT:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-4-2bcc42ab0b46> in <module>
2 pass
3
----> 4 x = DoAdd42(4)
TypeError: Can't instantiate abstract class DoAdd42 with abstract methods do_something
We will do it the correct way in the following example, in which we define two classes inheriting from our abstract class:
class DoAdd42(AbstractClassExample):
def do_something(self):
return self.value 42
class DoMul42(AbstractClassExample):
def do_something(self):
return self.value * 42
x = DoAdd42(10)
y = DoMul42(10)
print(x.do_something())
print(y.do_something())
OUTPUT:
52
420
A class that is derived from an abstract class cannot be instantiated unless all of its abstract methods are overridden.
You may think that abstract methods can't be implemented in the abstract base class. This impression is wrong: An abstract method can have an implementation in the abstract class! Even if they are implemented, designers of subclasses will be forced to override the implementation. Like in other cases of "normal" inheritance, the abstract method can be invoked with super() call mechanism. This enables providing some basic functionality in the abstract method, which can be enriched by the subclass implementation.
from abc import ABC, abstractmethod
class AbstractClassExample(ABC):
@abstractmethod
def do_something(self):
print("Some implementation!")
class AnotherSubclass(AbstractClassExample):
def do_something(self):
super().do_something()
print("The enrichment from AnotherSubclass")
x = AnotherSubclass()
x.do_something()
OUTPUT:
Some implementation!
The enrichment from AnotherSubclass
PS. Answer is shamefully copied from the-abc-of-abstract-base-classes, as i find no better go way to explain in easier term.