Implemention of Abstract in python - python

In python to implement an abstract class, we have to import the following:
from abc import ABCMeta, abstractmethod
In the above import statement what is the purpose of abstractmethod?
If it is a decorator, what's the exact operation its performing?

From the documentation:
#abc.abstractmethod
A decorator indicating abstract methods.
Using this decorator requires that the class’s metaclass is ABCMeta or is derived from it. A class that has a metaclass derived from ABCMeta cannot be instantiated unless all of its abstract methods and properties are overridden. The abstract methods can be called using any of the normal ‘super’ call mechanisms. abstractmethod() may be used to declare abstract methods for properties and descriptors.

Related

Is it OK to define optional methods on abstract base class?

Is it a good practice to have non-abstract methods on abstract base classes? I mean, methods that can, but don't have to, be present on subclasses of particular ABC?
Technically it is possible, as seen in the below example (ConcreteDataProvider does not implement disconnect; it only has to implement connect):
from abc import ABC, abstractmethod
class AbstractDataProvider(ABC):
#abstractmethod
def connect(self):
pass
def disconnect(self):
pass
class ConcreteDataProvider(AbstractDataProvider):
def connect(self):
pass
data_provider = ConcreteDataProvider()
It is fine to have ABC with concrete methods to provide default implementations. The standard library has several such cases:
The example of using abc.ABCMeta provides a non-abstract method.
The get_iterator() method is also part of the MyIterable abstract base class, but it does not have to be overridden in non-abstract derived classes.
The ABCs of the collections.abc module provide default methods (termed "Mixin Methods").
ABC
Inherits from
Abstract Methods
Mixin Methods
...
...
...
...
Iterator
Iterable
__next__
__iter__
Generator
Iterator
send, throw
close, __iter__, __next__
...
...
...
...
When "do nothing" is a sensible default, there is no problem with a concrete method having a default implementation that is just pass. This can especially be useful when you expect that many implementations will need this method: by providing a default, it is safe for client code to always call this method.
Note: When the pattern is specifically connect/disconnect, open/close, or similar pairs of methods to be called before/after usage, the __enter__/__exit__ pair of a context manager is the appropriate interface.

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

Do ABCs enforce method decorators?

I'm trying to figure out how to ensure that a method of a class inheriting from an ABC is created using the appropriate decorator. I understand (hopefully) how ABCs work in general.
from abc import ABCMeta, abstractmethod
class MyABC(metaclass=ABCMeta):
#abstractmethod
def my_abstract_method(self):
pass
class MyClass(MyABC):
pass
MyClass()
This gives "TypeError: Can't instantiate abstract class MyClass with abstract methods my_abstract_method". Great, makes sense. Just create a method with that name.
class MyClass(MyABC):
def my_abstract_method(self):
pass
MyClass()
Boom. You're done. But what about this case?
from abc import ABCMeta, abstractmethod
class MyABC(metaclass=ABCMeta):
#property
#abstractmethod
def my_attribute(self):
pass
class MyClass(MyABC):
def my_attribute(self):
pass
MyClass()
The MyClass() call works even though my_attribute is not a property. I guess in the end all ABCs do is ensure that a method with a given name exists. Thats it. If you want more from it, you have to look at MyABC's source code and read the documentation. The decorators and comments there will inform you of how you need to construct your sub-class.
Do I have it right or am I missing something here?
You're correct that ABCs do not enforce that. There isn't a way to enforce something like "has a particular decorator". Decorators are just functions that return objects (e.g., property returns a property object). ABCMeta doesn't do anything to ensure that the defined attributes on the class are anything in particular; it just makes sure they are there. This "works" without errors:
class MyABC(metaclass=ABCMeta):
#abstractmethod
def my_abstract_method(self):
pass
class MyClass(MyABC):
my_abstract_method = 2
MyClass()
That is, ABCMeta doesn't even ensure that the abstract method as provided on the subclass is a method at all. There just has to be an attribute of some kind with that name,
You could certainly write your own metaclass that does more sophisticated checking to ensure that certain attributes have certain kinds of values, but that's beyond the scope of ABCMeta.

Python: how to define __new__ for MutableSequence derived class?

I'm trying to inherit from collections.MutableSequence:
class myList(MutableSequence):
def __new__(cls,*kwargs):
obj=MutableSequence.__new__(cls,*kwargs)
return obj
I get the error:
>>>a=myList()
>>>TypeError: Can't instantiate abstract class ContactMapList with abstract methods __delitem__, __getitem__, __len__, __setitem__, insert
I did not get any errors when I was deriving my class directly from the built-in list class in the same fashion:
class myList(list):
def __new__(cls,*kwargs):
obj=list.__new__(cls,*kwargs)
return obj
I've tried to search for ways to define a constructor for myList(MutableSequence) but with not luck :(
An abstract base class is a contract. It's a list of promises that any class deriving from it must keep.
The promises each of the collections classes make are listed in the docs. For example, anything inheriting from MutableSequence will have __getitem__, __setitem__, __delitem__ and some more.
You can't instantiate a contract!
When you make a class that inherits from an abstract base class, you don't inherit the methods. (Well... see note below.) You inherit a bunch of "abstract methods" which are just placeholders. To fulfill the promise you made by inheriting from the ABC, you have to give definitions for these methods. They can do whatever you like, but they must be there.
Actually, the methods you inherit can be real methods and you can delegate to them with super(). This lets you specify default behaviours. But that's not often used.
You can't instantiate an abstract class; you can instantiate a non-abstract class. That answers your question.
The unanswered question is: why are you defining __new__ in the first place?

Categories