How can I make a class or method abstract in Python?
I tried redefining
__new__() like so:
class F: def __new__(cls): raise Exception("Unable to create an instance of abstract class %s" %cls)
but now if I create a class
G that inherits from
F like so:
class G(F): pass
then I can't instantiate
G either, since it calls its super class's
Is there a better way to define an abstract class?
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, abstractmethod class Abstract(ABC): @abstractmethod def foo(self): pass
# Python 3.0+ from abc import ABCMeta, abstractmethod class Abstract(metaclass=ABCMeta): @abstractmethod def foo(self): pass
# Python 2 from abc import ABCMeta, abstractmethod class 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