Python- Abstract Class and Method

Abstract class are a blueprint for other classes and is considered as the class designer.

A class whn designed needs a concrete implementation. Abstract class hold a contract between a designer and the implementer.

Instance of Abstract class cannot be created and it needs to be inherited and implemented in the subclass.

For a larger functional unit or a generic/common functionlaity is to be provided use Abstract class. Abstract class allows to implement the fucntionlaity in the subclass.

Abstract method allows to declare the method and impelement the functionality in the subclasses where the Abstract class is inherited.

A method in class can be decorated/marked as abstract with @abstractmethod keyword. Use Import abc to use the Abstract method.

See below example of using Abstract method-

Here abc is imported and the print_output method is decorated as @abstractmethod. The definition of such method is pass which means a control is passed to the subclasses where a implementation is expected for printing based on the output device.

The print_out method is implemented in Printer and Console subclasses inherited from class having a abstract method.

TypeError

Python raises a TypeError if we try to instantitate a Abstract Class.

TypeError: Can’t instantiate abstract class OutputDevice with abstract method print_output

Python also raises error if the subclass doesn’t implement the abstract method in suclass.

See the below example for TypeErrors whilst using Abstract Class

Here the Log class does not implement the print_output abstract method.

You can also see the various usage of Static Methods, ClassMethods and there difference’s.

Difference between Static, abstract and Class Methods in Python

Class MethodStatic Method
requires “cls” as first parameter does not require parameters
has the ability to access the state of objectdoes not influence the state of the object
method decorated with @classmethodmethod decorated with @staticmethod
they can be used to create objectscan be only used as a helper method
More about @classmethodMore about @staticmethod
Abstract Method
requires to import abc package and abc.ABC as first parameter
cannot be instanted, gives TypeError is tried to instantiate Abstract Class
method decorated with @abstractmethod
can be used as super class and implementation should be in subclass
More about @abstractmethod

Python- Static Methods

Static Methods can be used when Class object is not required to call a method but the method’s within that class are related to execute the code.

Also static methods can be used when the state of the object is not required to maintain. i.e. they don’t have the ability to change the state of the object

Decorate class method with @staticmethod keyword to make the method static.

See below example of using Static Method-

validate_instance_counter(param) method is marked as static method.

Add multiple constructor to Python Class

Python does not explicitly support multiple constructors in class. But there are ways you can provision a class with multiple constructors.

  1. Constructor Overloading using arguments
  2. Calling methods from constructors
  3. Using Class Method decorator

Constructor Overloading using arguments

Constructor overloading can be achieved using the same __init__ method and writing the functionality in the constructor method based on arguments.

See below example-

Calling methods from constructors

Same as above example the below example calls the method from the constructor based on the isntance of the argument.

Python- Class Method

Class Methods are like Class Varaibles which works on Class but not on object level.

So this methods are bound to class and not object. See class varaibles here

Clas Methods are decorated with @classmethod attribute to the method in class.

This method can be called without creating instance of the class.

See below example definition and usage of class method.

In the above example get_instance_counter() method is decorated as @classmethod and a cls variable is passed. This holdsthe class reference for which the method is called.

The constructor works normal with __init__ method and updates calss variable counter increments the counter when an instance is created. This class variable accessed in the get_instance_counter() method.

You can also provision Python class to have multiple constructor with class method. See here – How to add multiple constructor to Python class?

Python- Decorator Stacking

Python allows to apply multiple decorators to callable object.

The decorator function is called based on the order or the sequence it has been listed.

Decorator can also use there own arguments. In the below example @log decorator a parameter is passed with value ‘log sample’.

Log decorator has 2 wrapper functions. Outer function accepts the reference or pointer to the decorated fucntion and an internal function holds arguments that are passed to the decorated fucntion.

The decorated function is called from the internal wrapper function along with the parameters.

The parameter passed to the decorator is also assessible in the decorator function.

Coming back to Decorator stacking. The below example is used to decorate the fucntion with multiple decorators. Here log and executiontime are decorator function and stacked on the decorated function i.e. sample

Python- Decorator functions

Decorators are very useful for refactoring or debugging the code.

Decorators are used to but not limited to do the following –

  • validate the arguments
  • modiy the arguments
  • modify the returned objects
  • message logging
  • caching

See below code snippet calls the log function to the decorator method which returns the log function.

Other way to perform the same is by decorating the method with @decorator method which widely in Python

The above example can be rewritten with following code snippet. Here the calling function is decorated with log function which returns

Arguments passed to the deocrated function can also be made available to the decorator function using *args and **kwargs

See below example for same. Here the decorator calls the decorated function and prints the same. This way you can log the execution of decorated function. Log the time the parameters, output and time taken to execute the fucntion.

This way decorator function can be made global.

Python – Method Resolution Order

Multiple inheritnace is possible in Python but it comes with the Diamond Problem as seen in the diagram below.

Class A is super class of Class B and Class C

Class D is sub-class of Class B and Class C

When instance of Class D is created which Class method will be called? This is a Diamond Problem

MRO will in this case execute the method of the Class B. i.e. in multiple inheritance the method of first in the super class is executed from left to right. If that method does not exists in first super class then will try and check in the second and finally to the parent class.

Use info() method to know which super class method will be executed. See below code snippet

But there are issues with MRO too. If the Class D inherits Class A and Class C it throws error – Cannot create a consistent MRO. See below code.

Python – Magic methods

Did you know Python internally uses magic method for operators e.g. for + operator uses __add__() method

number = 10
print(number + 10)

#internally calls __add__() method

print(number.__add__(20))

The “+” operator depends on the type of the values been added i.e. int, float,string etc.

Now adding 2 integer or float values will add the values while for string it will concatenate the string.

But what about the objects? See below example when 2 objects are added it throws error.

This can be resolved with the magic method i.e. using __add__()

See below example. Here the “+” operator when used on objects calls the __add__() method.

How to know such magic methods for various types? Use help() method

help() method displays documentation for the

help(int)
help(str)
help(float)
help(bool)

Here is a list of operators to magic method mapping-

Comparision methods

OperatorMagic methodImplementation meaning or purpose
==__eq__(self, other)equality operator
!=__ne__(self, other)inequality operator
<__lt__(self, other)less-than operator
>__gt__(self, other)greater-than operator
<=__le__(self, other)less-than-or-equal-to operator
>=__ge__(self, other)greater-than-or-equal-to operato

Unary Operators

OperatorMagic methodImplementation meaning or purpose
+__pos__(self)unary positive, like a = +b
__neg__(self)unary negative, like a = -b
abs()__abs__(self)behavior for abs() function
round(a, b)__round__(self, b)behavior for round() function

Binary Operators

OperatorMagic methodImplementation meaning or purpose
+__add__(self, other)addition operator
__sub__(self, other)subtraction operator
*__mul__(self, other)multiplication operator
//__floordiv__(self, other)integer division operator
/__div__(self, other)division operator
%__mod__(self, other)modulo operator
**__pow__(self, other)exponential (power) operator

Unary Operators and assignments

OperatorMagic methodImplementation meaning or purpose
+=__iadd__(self, other)addition and assignment operator
-=__isub__(self, other)subtraction and assignment operator
*=__imul__(self, other)multiplication and assignment operator
//=__ifloordiv__(self, other)integer division and assignment operator
/=__idiv__(self, other)division and assignment operator
%=__imod__(self, other)modulo and assignment operator
**=__ipow__(self, other)exponential (power) and assignment operator

Type conversion methods

FunctionMagic methodImplementation meaning or purpose
int()__int__(self)conversion to integer type
float()__float__(self)conversion to float type
oct()__oct__(self)conversion to string, containing an octal representation
hex()__hex__(self)conversion to string, containing a hexadecimal representation

Object introspection

FunctionMagic methodImplementation meaning or purpose
str()__str__(self)responsible for handling str() function calls
repr()__repr__(self)responsible for handling repr() function calls
format()__format__(self, formatstr)called when new-style string formatting is applied to an object
hash()__hash__(self)responsible for handling hash() function calls
dir()__dir__(self)responsible for handling dir() function calls
bool()__nonzero__(self)responsible for handling bool() function calls

Object retrospection

FunctionMagic methodImplementation meaning or purpose
isinstance(object, class)__instancecheck__(self, object)responsible for handling isinstance() function calls
issubclass(subclass, class)__subclasscheck__(self, subclass)responsible for handling issubclass() function calls

Object attribute access

Expression exampleMagic methodImplementation meaning or purpose
object.attribute__getattr__(self, attribute)responsible for handling access to a non-existing attribute
object.attribute__getattribute__(self, attribute)responsible for handling access to an existing attribute
object.attribute = value__setattr__(self, attribute, value)responsible for setting an attribute value
del object.attribute__delattr__(self, attribute)responsible for deleting an attribute

Methods allowing access to containers

Expression exampleMagic methodImplementation meaning or purpose
len(container)__len__(self)returns the length (number of elements) of the container
container[key]__getitem__(self, key)responsible for accessing (fetching) an element identified by the key argument
container[key] = value__setitem__(self, key, value)responsible for setting a value to an element identified by the key argument
del container[key]__delitem__(self, key)responsible for deleting an element identified by the key argument
for element in container__iter__(self)returns an iterator for the container
item in container__contains__(self, item)responds to the question: does the container contain the selected item?

References – https://docs.python.org/3/reference/datamodel.html#special-method-names

Python – Creating and Accessing Class Variables

How to access the class variables without even creating a instance of class?

Class varaibles are created during class construction hence these variables are accessible even before an instance of class is created.

In below code preview_var variable is accessible even before creating and instance of class.

The class variables (preview_var) can also be accessed with the class instance.

You can also see all the class variables with __dict__ property

A class variable is accessible even before the instance of the class is created. You can use these varaibles to load any metadata information.

But a class varaible is cannot be accessed in class instance __dict__ property. See below code sample for object of class i.e. preview __dict__ property does not show class variable and is empty.

Now if you try to update the class variable with the instance of the class the content of the class variable will be only accesible to that instance and not the other instance.

See below example-

preview instance content is changed and is only accessible to that instance while preview1 instance still has the original content for class_var

While class varaibles as mentioned above holds different content for various instance of same class, they are also called as shared variables only when these class varaibles are changed within the class accessed by the class and not the instance of that class.

Below example shows the instances of the Preview class where the counter incremented when the instance is created but the counter value is shared and can be accessed with the class and instance variable. What is instance variable? see here

see constructor of the class updates the counter accessed by the class. i.e. Preview.counter

I hope this helps to understand class.shared variables and different ways of accessing same.