How define constructor implementation for an Abstract Class in Python?

Question:

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?

Asked By: dabadaba

||

Answers:

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.
Answered By: gipsy

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

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__
Answered By: Mike Müller

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
Answered By: Ashwini Chaudhary

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

Answered By: Tiger

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

Answered By: N Amit Singh