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?
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.
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__
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
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
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
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?
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.
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__
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
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
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 fun1Process finished with exit code 1