How to Make Abstract Classes in Python

Is it possible to make abstract classes?

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, 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>

Best way to implement abstract classes in Python

If you really want the error to be raised if one of the subclasses try to call the superclass abstract method, then, yes, you should raise it manually. (and then, create an instance of the Exception class to the raise command raise NotImplementedError() even if it works with the class directly)

However, the existing behavior is actually convenient: if your abstractmethod contains just a pass, then you can have any number of sub-classes inheriting your base class, and as long as at least one implements the abstractmethod, it will work. Even if all of them call the super() equivalent method, without checking anything else.

If an error - NotImplementedError or any other, would be called, in a complex hierarchy, making use of mixins, and such, you'd need to check at each time you'd call super if the error was raised, just to skipt it. For the record, checking if super() would hit the class where method is abstract with a conditional is possible, this way:

if not getattr(super().foo, "__isabstractmethod__", False):
super().foo(...)

Since what do you want if you reach the base of the hierarchy for a method is for it to do nothing, it is far simples if just nothing happens!

I mean, check this:

class A(abc.ABC):
@abstractmethod
def validate(self, **kwargs):
pass

class B(A):
def validate(self, *, first_arg_for_B, second_arg_for_B=None, **kwargs):
super().validate(**kwargs)
# perform validation:
...

class C(A)
def validate(self, *, first_arg_for_C **kwargs):
super().validate(**kwargs)
# perform validation:
...

class Final(B, C):
...

Neither B.validate nor C.validate need to worry about any other class in the hierarchy, just do their thing and pass on.
If A.validate would raise, both methods would have to do super().validate(...) inside a try: ...;except ...:pass statement, or inside a weird if block, for the gain of...nothing.

update - I just found this note on the oficial documentation:

Note Unlike Java abstract methods, these abstract methods may have an
implementation. This implementation can be called via the super()
mechanism from the class that overrides it. This could be useful as an
end-point for a super-call in a framework that uses cooperative
multiple-inheritance.
https://docs.python.org/3/library/abc.html#abc.abstractmethod

I will even return you a personal question, if you can reply in the comments: I understand it is much less relevant in Java where one can't have multiple inheritance, so, even in a big hierarchy, the first subclass to implement the abstract method would usually be well known. But otherwise, in a Java project were one could pick one of various Base concrete classes, and proceed with others in an arbitrary order, since the abstractmethod raises, how is that resolved?

How define constructor implementation for an Abstract Class in 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__

Where should I put abstract classes in a python package?

No convention comes to mind. If this is all for just one project, I'd be looking to put the abstract class in with the concrete subclasses at whatever level they're at. If all the subclasses were in one file, then I'd put the abstract class in that file too. If all the subclasses were in individual files in a dir, I'd put the abstract class right next to them in its own file. The reason I'd put the abstract class somewhere else is if I'm separating off utility code that can be reused with other projects. In short, an abstract class is just a piece of code. Just another class. Treat it like any other.

As far as naming, the natural naming of the class given what it is/does is usually enough. If your abstract class were Animal, and your subclasses were Goat, Horse, etc., I'd see no reason to call your abstract class AbstractAnimal, as it's pretty clear already what's going on...that you wouldn't instantiate Animal directly. Also, if you're looking at a class thinking of reusing it, and you see an abstract method in it, then you know it's abstract.

Python: Testing abstract class with concrete implementation details

Just create a subclass.

class TestAnimal(Animal):
def description(self):
return "foo"

assert TestAnimal().zoo_str() == "fooGet more info at zoo.com!"

Abstract class without any inheritance

It seems that you're trying to emulate namespaces. It's better to use modules. The mechanism is built into Python, and functions as a namespace:

https://docs.python.org/3/tutorial/modules.html

An abstract class with only static-methods can work as a namespace, but it's confusing to people reading the source code



Related Topics



Leave a reply



Submit