How define constructor implementation for an Abstract Class in Python?

PythonPython 2.7OopAbstract Class

Python Problem Overview


I am trying to declare an abstract class A with a constructor with a default behavior: all subclasses must initialize a member self.n:

from abc import ABCMeta

class A(object):
    __metaclass__ = ABCMeta
    
    def __init__(self, n):
        self.n = n

However, I do not want to let the A class be instantiated because, well, it is an abstract class. The problem is, this is actually allowed:

a = A(3)

This produces no errors, when I would expect it should.

So: how can I define an un-instantiable abstract class while defining a default behavior for the constructor?

Python Solutions


Solution 1 - Python

Making the __init__ an abstract method:

from abc import ABCMeta, abstractmethod

class A(object):
    __metaclass__ = ABCMeta

    @abstractmethod
    def __init__(self, n):
        self.n = n


if __name__ == '__main__':
    a = A(3)

helps:

TypeError: Can't instantiate abstract class A with abstract methods __init__

Python 3 version:

from abc import ABCMeta, abstractmethod

class A(object, metaclass=ABCMeta):

    @abstractmethod
    def __init__(self, n):
        self.n = n


if __name__ == '__main__':
    a = A(3)

Works as well:

TypeError: Can't instantiate abstract class A with abstract methods __init__

Solution 2 - Python

A not so elegant solution can be this:

class A(object):
  def __init__(self, n):
    if self.__class__ == A:
      raise Exception('I am abstract!')
    self.n = n

Usage

class B(A):
  pass
a = A(1)  # Will throw exception
b = B(1)  # Works fine as expected.

Solution 3 - Python

You can override __new__ method to prevent direct instantiation.

class A(object):
    __metaclass__ = ABCMeta

    def __new__(cls, *args, **kwargs):
        if cls is A:
            raise TypeError(
                "TypeError: Can't instantiate abstract class {name} directly".format(name=cls.__name__)
            )
        return object.__new__(cls)

Output:

>>> A()
Traceback (most recent call last):
  File "<ipython-input-8-3cd318a12eea>", line 1, in <module>
    A()
  File "/Users/ashwini/py/so.py", line 11, in __new__
    "TypeError: Can't instantiate abstract class {name} directly".format(name=cls.__name__)
TypeError: TypeError: Can't instantiate abstract class A directly

Solution 4 - Python

You should define the methods as abstract as well with the @abc.abstractmethod decorator.

Solution 5 - Python

You can implement something like below :

from abc import ABC
class A(ABC):
    def __init__(self, n):
        self.n = n
        super(A,self).__init__()

Instantiating this class would throw an error

Solution 6 - Python

> I do not want to let the A class be instantiated because, well, it is an abstract class. The problem is, this is actually allowed

Python on its own doesn't provide abstract classes. 'abc' module which provides the infrastructure for defining Abstract Base Classes.

Abstract classes are classes that contain one or more abstract methods. In your case code still an abstract class that should provide "Abstract classes cannot be instantiated" behavior.

If you don't want to allow, program need corrections: i.e add decorator @abstractmethod. Below code executed in python 3.6

from abc import ABC, abstractmethod

class Myabs(ABC):

    def __init__(self, connection):
        self.connection = connection
        print("1. calling from base init : {}".format(self.connection))
        super(Myabs, self).__init__()
    @abstractmethod
    def fun1(self, val):
        pass

class D(Myabs):
    def fun1(self, val="hi"):
        print("calling from D: fun1")


object0 = Myabs('connection') # Python 3.6.9

output:

> ClassConcept/abs_class.py Traceback (most recent call last): File > "ClassConcept/abs_class.py", line 19, in > object0 = Myabs('connection') # Python 3.6.9 TypeError: Can't instantiate abstract class Myabs with abstract methods fun1 > > Process finished with exit code 1

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestiondabadabaView Question on Stackoverflow
Solution 1 - PythonMike MüllerView Answer on Stackoverflow
Solution 2 - PythongipsyView Answer on Stackoverflow
Solution 3 - PythonAshwini ChaudharyView Answer on Stackoverflow
Solution 4 - PythonIgnacio Vergara KauselView Answer on Stackoverflow
Solution 5 - PythonTigerView Answer on Stackoverflow
Solution 6 - PythonN Amit SinghView Answer on Stackoverflow