Abstract methods in Python - python

I need something like an abstract protected method in Python (3.2):
class Abstract:
def use_concrete_implementation(self):
print(self._concrete_method())
def _concrete_method(self):
raise NotImplementedError()
class Concrete(Abstract):
def _concrete_method(self):
return 2 * 3
Is it actually useful to define an "abstract" method only to raise a NotImplementedError?
Is it good style to use an underscore for abstract methods, that would be protected in other languages?
Would an abstract base class (abc) improve anything?

In Python, you usually avoid having such abstract methods alltogether. You define an interface by the documentation, and simply assume the objects that are passed in fulfil that interface ("duck typing").
If you really want to define an abstract base class with abstract methods, this can be done using the abc module:
from abc import ABCMeta, abstractmethod
class Abstract(metaclass=ABCMeta):
def use_concrete_implementation(self):
print(self._concrete_method())
#abstractmethod
def _concrete_method(self):
pass
class Concrete(Abstract):
def _concrete_method(self):
return 2 * 3
Again, that is not the usual Python way to do things. One of the main objectives of the abc module was to introduce a mechanism to overload isinstance(), but isinstance() checks are normally avoided in favour of duck typing. Use it if you need it, but not as a general pattern for defining interfaces.

When in doubt, do as Guido does.
No underscore. Just define the "abstract method" as a one-liner which raises NotImplementedError:
class Abstract():
def ConcreteMethod(self):
raise NotImplementedError("error message")

Basically, an empty method in the base class is not necessary here. Just do it like this:
class Abstract:
def use_concrete_implementation(self):
print(self._concrete_method())
class Concrete(Abstract):
def _concrete_method(self):
return 2 * 3
In fact, you usually don't even need the base class in Python. Since all calls are resolved dynamically, if the method is present, it will be invoked, if not, an AttributeError will be raised.
Attention: It is import to mention in the documentation that _concrete_method needs to be implemented in subclasses.

Related

Why we declare metaclass=abc.ABCMeta when use abstract class in python?

When I was reading the code online, I have encountered the following cases of using abstract classes:
from abc import abstractmethod,ABCMeta
class Generator(object,metaclass=ABCMeta):
#abstractmethod
def generate(self):
raise NotImplementedError("method not implemented")
generator=Generator()
generator.generate()
The following error is returned, as expected:
TypeError: Can't instantiate abstract class Generator with abstract methods generate
But if I write it like this (the only difference is in the second line)
from abc import abstractmethod,ABCMeta
class Generator(object):
#abstractmethod
def generate(self):
raise NotImplementedError("method not implemented")
generator=Generator()
generator.generate()
Although there are changes in the error message,
NotImplementedError: method not implemented
When I implemented the generate method, both of the above ways of Generator were executed correctly,
class GeneticAlgorithm(Generator):
def generate(self):
print("ABC")
ga=GeneticAlgorithm()
ga.generate()
>>> ABC
So why do we need the statement metaclass=ABCMeta?
I know something from GeeksforGeeks that
ABCMeta metaclass provides a method called register method that can be invoked by its instance. By using this register method, any abstract base class can become an ancestor of any arbitrary concrete class.
But this still doesn't make me understand the necessity of declaring metaclass=ABCMeta, it feels like #abstractmethod modifying the method is enough.
You "need" the metaclass=ABCMeta to enforce the rules at instantiation time.
generator=Generator() # Errors immediately when using ABCMeta
generator.generate() # Only errors if and when you call generate otherwise
Imagine if the class had several abstract methods, only some of which were implemented in a child. It might work for quite a while, and only error when you got around to calling an unimplemented method. Failing eagerly before you rely on the ABC is generally a good thing, in the same way it's usually better for a function to raise an exception rather than just returning None to indicate failure; you want to know as soon as things are wrong, not get a weird error later without knowing the ultimate cause of the error.
Side-note: There's a much more succinct way to be an ABC than explicitly using the metaclass=ABCMeta syntax:
from abc import abstractmethod, ABC
class Generator(ABC):
Python almost always makes empty base classes that use the metaclass to simplify use (especially during the 2 to 3 transition period, where there was no compatible metaclass syntax that worked in both, and direct inheritance was the only thing that worked).
The second example,
from abc import abstractmethod,ABCMeta
class Generator(object):
#abstractmethod
def generate(self):
raise NotImplementedError("method not implemented")
generator=Generator()
generator.generate() # HERE it raises
does not use the #abstractclass decorator in any way. It only raises the NotImplemetedError exception when the generate() function is called, whereas in the first example an error is raised on the instantiation (generator=Generator()).
In order to use #abstractmethod, the class has to have metaclass ABCMeta (or it has to inherit from such class, e.g. ABC).
By the way, there are ways to check whether a method is implemented even sooner (on class definition) using, for example __init_subclass__ or by defining a custom metaclass and modifying its __new__ method.

Must a class implement all abstract methods?

Suppose you have the following class:
class Base(object):
def abstract_method(self):
raise NotImplementedError
Can you then implement a inheriting class, which does not implement the abstract method? For example, when it does not need that specific method. Will that give problems or is it just bad practice?
If you're implementing abstract methods the way you show, there's nothing enforcing the abstractness of the class as a whole, only of the methods that don't have a concrete definition. So you can create an instance of Base, not only of its subclasses.
b = Base() # this works following your code, only b.abstract_method() raises
def Derived(Base):
... # no concrete implementation of abstract_method, so this class works the same
However, if you use the abc module from the standard library to designate abstract methods, it will not allow you to instantiate an instance of any class that does not have a concrete implementation of any abstract methods it has inherited. You can leave inherited abstract methods unimplemented in an intermediate abstract base class (e.g. a subclass of the original base, that is itself intended to still be abstract), but you can't make any instances.
Here's what using abc looks like:
from abc import ABCMeta, abstractmethod
class ABCBase(metaclass=ABCMeta):
#abstractmethod
def abstract_method(self, arg):
...
class ABCDerived(ABCBase):
... # we don't implement abstract_method here, so we're also an abstract class
d = ABCDerived() # raises an error

Is it a good practice to put common methods to an abstract class in Python?

I'm using the abc module to define an interface that subclasses must support. There're also some common methods that are present in all subclasses. Is it ok to put them in the abstract class or should that only contain abstract methods (i.e. decorated with #abc.abstractmethod) ?
TL; DR; Yes, it is OK for an abstract class to have non-abstract methods.
Typically what we call an abstract class is just a class that cannot be instantiated.
On the other hand what we call an interface is a class which has only method declarations but no implementations. In particular its an abstract class because it doesn't have a constructor.
Of course in Python there are no real interfaces: every method has to have a body. But we can somewhat emulate interfaces via raise NotImplementedError().
Anyway interfaces form a subset of abstract classes. This obviously suggests that there are abstract classes that are not interfaces. This is exactly the case you are describing. Yes, abstract class may contain implemented, non-abstract methods. And it is not a bad practice. This is especially useful when a given method does not depend on concrete implementation.
For example consider an interface for a generic parser (I'm thinking about json.load and json.loads):
class ILoader(ABC):
#abstractmethod
def load(self, stream):
raise NotImplementedError()
It's completely OK to give loads method which accepts a string instead of stream with a default implementation:
class AbstractLoader(ABC):
#abstractmethod
def load(self, stream):
raise NotImplementedError()
def loads(self, text):
stream = io.StringIO(text)
return self.load(stream)
although I would use Abstract prefix instead of I. ;)

Is there any need of using abstract static/class methods?

For example, in Python you can define abstract class with abstract methods within abc module and it works well. Moreover since version 3.3 you can mix abstractmethod decorator with staticmethod or classmethod decorator legally.
class IDeployer(abc.ABC):
#staticmethod
#abc.abstractmethod
def get_host_type():
raise NotImplementedError()
But ability to mix these decorators doesn't imply the need to do so.
Can I mix these decorators or it will surely point out ill-designed interface?
PS: yes, I know that Python ABC mechanism won't really oblige inheritors to define methods being static/class methods correspondingly. Even abstract method's signature can be changed by inheritors in Python.

Difference between abstract class and interface in Python

What is the difference between abstract class and interface in Python?
What you'll see sometimes is the following:
class Abstract1:
"""Some description that tells you it's abstract,
often listing the methods you're expected to supply."""
def aMethod(self):
raise NotImplementedError("Should have implemented this")
Because Python doesn't have (and doesn't need) a formal Interface contract, the Java-style distinction between abstraction and interface doesn't exist. If someone goes through the effort to define a formal interface, it will also be an abstract class. The only differences would be in the stated intent in the docstring.
And the difference between abstract and interface is a hairsplitting thing when you have duck typing.
Java uses interfaces because it doesn't have multiple inheritance.
Because Python has multiple inheritance, you may also see something like this
class SomeAbstraction:
pass # lots of stuff - but missing something
class Mixin1:
def something(self):
pass # one implementation
class Mixin2:
def something(self):
pass # another
class Concrete1(SomeAbstraction, Mixin1):
pass
class Concrete2(SomeAbstraction, Mixin2):
pass
This uses a kind of abstract superclass with mixins to create concrete subclasses that are disjoint.
What is the difference between abstract class and interface in Python?
An interface, for an object, is a set of methods and attributes on that object.
In Python, we can use an abstract base class to define and enforce an interface.
Using an Abstract Base Class
For example, say we want to use one of the abstract base classes from the collections module:
import collections
class MySet(collections.Set):
pass
If we try to use it, we get an TypeError because the class we created does not support the expected behavior of sets:
>>> MySet()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class MySet with abstract methods
__contains__, __iter__, __len__
So we are required to implement at least __contains__, __iter__, and __len__. Let's use this implementation example from the documentation:
class ListBasedSet(collections.Set):
"""Alternate set implementation favoring space over speed
and not requiring the set elements to be hashable.
"""
def __init__(self, iterable):
self.elements = lst = []
for value in iterable:
if value not in lst:
lst.append(value)
def __iter__(self):
return iter(self.elements)
def __contains__(self, value):
return value in self.elements
def __len__(self):
return len(self.elements)
s1 = ListBasedSet('abcdef')
s2 = ListBasedSet('defghi')
overlap = s1 & s2
Implementation: Creating an Abstract Base Class
We can create our own Abstract Base Class by setting the metaclass to abc.ABCMeta and using the abc.abstractmethod decorator on relevant methods. The metaclass will be add the decorated functions to the __abstractmethods__ attribute, preventing instantiation until those are defined.
import abc
For example, "effable" is defined as something that can be expressed in words. Say we wanted to define an abstract base class that is effable, in Python 2:
class Effable(object):
__metaclass__ = abc.ABCMeta
#abc.abstractmethod
def __str__(self):
raise NotImplementedError('users must define __str__ to use this base class')
Or in Python 3, with the slight change in metaclass declaration:
class Effable(object, metaclass=abc.ABCMeta):
#abc.abstractmethod
def __str__(self):
raise NotImplementedError('users must define __str__ to use this base class')
Now if we try to create an effable object without implementing the interface:
class MyEffable(Effable):
pass
and attempt to instantiate it:
>>> MyEffable()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class MyEffable with abstract methods __str__
We are told that we haven't finished the job.
Now if we comply by providing the expected interface:
class MyEffable(Effable):
def __str__(self):
return 'expressable!'
we are then able to use the concrete version of the class derived from the abstract one:
>>> me = MyEffable()
>>> print(me)
expressable!
There are other things we could do with this, like register virtual subclasses that already implement these interfaces, but I think that is beyond the scope of this question. The other methods demonstrated here would have to adapt this method using the abc module to do so, however.
Conclusion
We have demonstrated that the creation of an Abstract Base Class defines interfaces for custom objects in Python.
Python >= 2.6 has Abstract Base Classes.
Abstract Base Classes (abbreviated
ABCs) complement duck-typing by
providing a way to define interfaces
when other techniques like hasattr()
would be clumsy. Python comes with
many builtin ABCs for data structures
(in the collections module), numbers
(in the numbers module), and streams
(in the io module). You can create
your own ABC with the abc module.
There is also the Zope Interface module, which is used by projects outside of zope, like twisted. I'm not really familiar with it, but there's a wiki page here that might help.
In general, you don't need the concept of abstract classes, or interfaces in python (edited - see S.Lott's answer for details).
In a more basic way to explain:
An interface is sort of like an empty muffin pan.
It's a class file with a set of method definitions that have no code.
An abstract class is the same thing, but not all functions need to be empty. Some can have code. It's not strictly empty.
Why differentiate:
There's not much practical difference in Python, but on the planning level for a large project, it could be more common to talk about interfaces, since there's no code. Especially if you're working with Java programmers who are accustomed to the term.
Python doesn't really have either concept.
It uses duck typing, which removed the need for interfaces (at least for the computer :-))
Python <= 2.5:
Base classes obviously exist, but there is no explicit way to mark a method as 'pure virtual', so the class isn't really abstract.
Python >= 2.6:
Abstract base classes do exist (http://docs.python.org/library/abc.html). And allow you to specify methods that must be implemented in subclasses. I don't much like the syntax, but the feature is there. Most of the time it's probably better to use duck typing from the 'using' client side.
In general, interfaces are used only in languages that use the single-inheritance class model. In these single-inheritance languages, interfaces are typically used if any class could use a particular method or set of methods. Also in these single-inheritance languages, abstract classes are used to either have defined class variables in addition to none or more methods, or to exploit the single-inheritance model to limit the range of classes that could use a set of methods.
Languages that support the multiple-inheritance model tend to use only classes or abstract base classes and not interfaces. Since Python supports multiple inheritance, it does not use interfaces and you would want to use base classes or abstract base classes.
http://docs.python.org/library/abc.html
Abstract classes are classes that contain one or more abstract methods. Along with abstract methods, Abstract classes can have static, class and instance methods.
But in case of interface, it will only have abstract methods not other. Hence it is not compulsory to inherit abstract class but it is compulsory to inherit interface.
For completeness, we should mention PEP3119
where ABC was introduced and compared with interfaces,
and original Talin's comment.
The abstract class is not perfect interface:
belongs to the inheritance hierarchy
is mutable
But if you consider writing it your own way:
def some_function(self):
raise NotImplementedError()
interface = type(
'your_interface', (object,),
{'extra_func': some_function,
'__slots__': ['extra_func', ...]
...
'__instancecheck__': your_instance_checker,
'__subclasscheck__': your_subclass_checker
...
}
)
ok, rather as a class
or as a metaclass
and fighting with python to achieve the immutable object
and doing refactoring
...
you'll quite fast realize that you're inventing the wheel
to eventually achieve
abc.ABCMeta
abc.ABCMeta was proposed as a useful addition of the missing interface functionality,
and that's fair enough in a language like python.
Certainly, it was able to be enhanced better whilst writing version 3, and adding new syntax and immutable interface concept ...
Conclusion:
The abc.ABCMeta IS "pythonic" interface in python

Categories