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
Get Screenshot on Windows with Python
How Does Python Manage Int and Long
How to Install Python Opencv Through Conda
Test If Executable Exists in Python
How to Save a Dictionary to a File
Common Xlabel/Ylabel for Matplotlib Subplots
Open File in a Relative Location in Python
Encoding an Image File with Base64
What Is the Performance Impact of Non-Unique Indexes in Pandas
What's the Best Way to Return Multiple Values from a Function
The Difference Between Sys.Stdout.Write and Print
How to Send an Email with Python
Django: Deploying an Application on Heroku with SQLite3 as the Database