The purpose of this blog is to happily share my learning and ideas to help people, who actively seek solutions for the day-to-day problems faced.

Recent Posts

Python: ABC (Abstract Base Classes) of python - Explained

Abstract:
In general, abstract refers to either theroetical/conceptual/non-representational concepts in the real world, At least that's what my search guru "Google" reported me as shown below,


abstract meaning

Now let's see what it actually means in the python world

Before we understand about Abstract Base Classes in python we must understand some of the pre-requisites, I will go through each of its one by one below,

Polymorphism:
The ability of an object to respond differently to different messages is what we call as polymorphism, Hence it is clear that it gives importance to the behaviour over structure of an object. So that raises to the next question

How to check an object behavior ?
Ah, that's easy we can simply make use of the isinstance() method to check nah ?
isinstance(someObj, list)

Nope, it will simply tell you the type of the object and not it's behavior buddy
Ideal scenario to check for behavior is something like this,
isBehavesLike(someObj, ListBehavior)

Behaviors and Delegation:
Good news, Yes we do have support for checking out such object behavior. We just need to implement such ListBehavior classes, one such class is "collections" module

Collections
In python, collections are special containers to hold data structures such as list, tuple, dict etc,. 
Not just that, this module in turn represent some of the interesting behaviors like mutable sequence, mappings etc,. 
It provides abstract base classes that can be used to test whether a class provides a particular interface such as whether it is hashable or mapping 

In [1]: import collections
In [2]: isinstance("ravic499", collections.Sequence)
Out[2]: True
In [3]: isinstance("ravic499", collections.Mapping)
Out[3]: False

This ability of using an object to check for the behavior is acheived using register method, collections module in turns using it as,

...
Sequence.register(tuple)
Sequence.register(str)
Sequence.register(range)
...
MutableMapping.register(dict)
...

For more details,
https://docs.python.org/3/library/collections.abc.html
https://github.com/python/cpython/blob/master/Lib/_collections_abc.py

Registering
To understand it better, first let's see a subclass in python

class ChildClass(ParentClass):
    pass

Here the child class knew who is the parent but not the other way around, Similarly we can create a virtual subclass in a way such that the parent class knew who is the child class is,

ParentClass.register(ChildClass)

This results in the creation of Abstract Base Classes
Fore more details - https://docs.python.org/3/glossary.html#term-abstract-base-class

Abstract Base Classes
Classes that can register other classes are called Abstract Base Class, by this way the Parent Class aware of its Child Classes. ABCs introduce virtual subclasses, which are classes that don’t inherit from a class but are still recognized by isinstance() and issubclass() methods

Remember registering is just a promise and not a check

In [1]: import collections
In [2]: class MyClass: pass
In [3]: issubclass(MyClass, collections.Sequence)
Out[3]: False
In [4]: collections.Sequence.register(MyClass)
In [5]: issubclass(MyClass, collections.Sequence)
Out[5]: True

Categories
We can say that ABC are categories, if you see here MyClass can behave like a Sequence and it can be labeled/tagged as sequence but remember it's just a promise and we don't have any valid checks

Build you own ABCs
A simple example of building our very own ABC is as follows

from abc import ABCMeta

class MyABC(metaclass=ABCMeta):
    pass

MyABC.register(tuple)

assert issubclass(tuple, MyABC)
assert isinstance((), MyABC)

Fore more details - https://docs.python.org/3/library/abc.html#module-abc

But wait.. Why do we need metaclasses

Metaclasses
When you build an instance you use a class, the class can put things into the instance, similarly we can also build a class using a metaclass, the metaclass can put things into the class
The reason for using metaclass is that we need our class to keep the register method such that our class will be able to register other classes so that we can tag/label them

Remember we can even use ABC as our parent class, ABC is just an extra layer over ABCMeta class i.e it implicitly defines the metaclass for us. Also the classes which further inherits from this abstract class can also have accees to this register method

ABCs as interfaces
We can use ABCs to build interfaces, it helps to enforces the structure of an object, for example my class must contain "myMethod" this can achieve using abstract method

Abstract Method:
Abstract methods are simply the methods created inside the abstract class with "@abstractmethod" decorator

Note: Here we don't implement the actual definition of the method, this is created just for name sake.

Syntax:

from abc import ABC, abstractmethod

class StatusInterface(ABC):

    @abstractmethod
    def status(self):
        pass

Now if we try to instantiate any object to the above abstract class, it will results in a below error,

si = StatusInterface()

TypeError: Can't instantiate abstract class StatusInterface with abstract methods status

Similarly if we don't implement the abstract method in our subclass then again it will complain when we try to instantiate an object

class MyStatusView(StatusInterface): pass

msv = MyStatusView()

TypeError: Can't instantiate abstract class MyStatusView with abstract methods status

By this way, abstract method ensures to enforce us to implement the definition for abstract method in the sub class

Usecase:
As we know, abstract class is a special class in python for which we don't create object or it's not instantiated, It's goal is to just give you an abstract without including the implementation details. i.e it hides details at the design level


Example: When we describe an object we inform in more abstract form, i.e Consider a vehicle which can move, here we didn't inform anything about where the vehicle moves whether its in a road, sails on the sea or flies in the air etc,.
Let us consider a simple usecase in which a animal can be differentiated among each other by its birth style,

from abc import ABC, abstractmethod

class Animal(ABC):

    @abstractmethod
    def birth_style(self):
        pass

class Mammals(Animal):

    def birth_style(self):
        print("Live Birth")

class Reptiles(Animal):

    def birth_style(self):
        print("Hatch Eggs")

m = Mammals()
m.birth_style()

r = Reptiles()

r.birth_style()

From the above example it is evident that both the Mammals and Reptiles inherit their characters from Animal class but the actual implementation is made at each of its sub-class level such that the base class is just used as a template or blue print to provide support for its sub class

Source Code:
Please click on the below git hub link for additional examples explained using python,
https://github.com/ravic499/blog-tips/blob/master/advanced_python/abstractclass.py

References:
https://www.youtube.com/watch?v=I9nXiJQnGsk&t=60s
https://www.youtube.com/watch?v=6Fs2MIf61oQ
https://www.youtube.com/watch?v=PDMe3wgAsWg

Also Read: http://ravic499.blogspot.com/2019/08/python-abstraction-encapsulation.html

No comments