Is it possible to make abstract classes in Python?
Use the abc
module to create abstract classes. Use the abstractmethod
decorator to declare a method abstract, and declare a class abstract using one of three ways, depending upon your Python version.
In Python 3.4 and above, you can inherit from ABC
. In earlier versions of Python, you need to specify your class's metaclass as ABCMeta
. Specifying the metaclass has different syntax in Python 3 and Python 2. The three possibilities are shown below:
# Python 3.4+from abc import ABC, abstractmethodclass Abstract(ABC): @abstractmethod def foo(self): pass
# Python 3.0+from abc import ABCMeta, abstractmethodclass Abstract(metaclass=ABCMeta): @abstractmethod def foo(self): pass
# Python 2from abc import ABCMeta, abstractmethodclass Abstract: __metaclass__ = ABCMeta @abstractmethod def foo(self): pass
Whichever way you use, you won't be able to instantiate an abstract class that has abstract methods, but will be able to instantiate a subclass that provides concrete definitions of those methods:
>>> Abstract()Traceback (most recent call last): File "<stdin>", line 1, in <module>TypeError: Can't instantiate abstract class Abstract with abstract methods foo>>> class StillAbstract(Abstract):... pass... >>> StillAbstract()Traceback (most recent call last): File "<stdin>", line 1, in <module>TypeError: Can't instantiate abstract class StillAbstract with abstract methods foo>>> class Concrete(Abstract):... def foo(self):... print('Hello, World')... >>> Concrete()<__main__.Concrete object at 0x7fc935d28898>
The old-school (pre-PEP 3119) way to do this is just to raise NotImplementedError
in the abstract class when an abstract method is called.
class Abstract(object): def foo(self): raise NotImplementedError('subclasses must override foo()!')class Derived(Abstract): def foo(self): print 'Hooray!'>>> d = Derived()>>> d.foo()Hooray!>>> a = Abstract()>>> a.foo()Traceback (most recent call last): [...]
This doesn't have the same nice properties as using the abc
module does. You can still instantiate the abstract base class itself, and you won't find your mistake until you call the abstract method at runtime.
But if you're dealing with a small set of simple classes, maybe with just a few abstract methods, this approach is a little easier than trying to wade through the abc
documentation.
Here's a very easy way without having to deal with the ABC module.
In the __init__
method of the class that you want to be an abstract class, you can check the "type" of self. If the type of self is the base class, then the caller is trying to instantiate the base class, so raise an exception. Here's a simple example:
class Base(): def __init__(self): if type(self) is Base: raise Exception('Base is an abstract class and cannot be instantiated directly') # Any initialization code print('In the __init__ method of the Base class')class Sub(Base): def __init__(self): print('In the __init__ method of the Sub class before calling __init__ of the Base class') super().__init__() print('In the __init__ method of the Sub class after calling __init__ of the Base class')subObj = Sub()baseObj = Base()
When run, it produces:
In the __init__ method of the Sub class before calling __init__ of the Base classIn the __init__ method of the Base classIn the __init__ method of the Sub class after calling __init__ of the Base classTraceback (most recent call last): File "/Users/irvkalb/Desktop/Demo files/Abstract.py", line 16, in <module> baseObj = Base() File "/Users/irvkalb/Desktop/Demo files/Abstract.py", line 4, in __init__ raise Exception('Base is an abstract class and cannot be instantiated directly')Exception: Base is an abstract class and cannot be instantiated directly
This shows that you can instantiate a subclass that inherits from a base class, but you cannot instantiate the base class directly.