The interface is a collection of method signatures in an object-oriented language like Python. It is provided when implementing class. The implementation of the interface is a technique for writing efficient code and using abstraction.
For the implementation of object interface in python, the zope.interface package is used. It is handled and maintained by a project called Zope Toolkit. This package is used for exporting two objects, namely, interface and attribute directly from the package.
Several helper methods are also exported by using this package. The main aim of this package is to provide hard semantics and better handling of error messages than that of an in-built module of python.
The interface in any object-oriented programming language acts as a blueprint in order to design classes and objects and hence they are implemented by using the decorator ‘implementer’ on the class.
If any class implements an interface then the instance of the same class provides the interface which means that the object class provides an interface directly along with what the class implements.
Below is the syntax of using ‘implementer’ for the class interface:
@zope.interface.implementer(*interfaces)
class Class_name:
# methods
Write a code to implement the interface in python
import zope.interface
class TestInterface(zope.interface.Interface):
y = zope.interface.Attribute("foo")
def methodName1(self, y):
pass
def methodName2(self):
pass
@zope.interface.implementer(TestInterface)
class TestClass:
def methodName1(self, y):
return y**2
def methodName2(self):
return "hello"
When the TestClass implements TestInterface, the instance of TestClass provides the TestInterface as seen from the code.
The interface is described by using the python class statement as well as its subclass which is interface.Interface, also known as the parent interface for all the interfaces present.
The Syntax for the same is:
class IMyInterface(zope.interface.Interface):
# methods and attributes
There are several methods provided by the class interface in python, a few of which are as follows:
| Method name | Description |
|---|---|
| implementedBy(class) | It is used for returning a boolean value, if the class implements the interface, then it returns true, else it returns false. |
| providedBy(object) | It returns a boolean value, if the object provides an interface then it returns true, else false. |
| providedBy(class) | This method implements the interface and hence it returns false. |
| list(zope.interface.implementedBy(class)) | This method is used for returning the list of interfaces that are implemented by a class. |
| list(zope.interface.providedBy(object)) | This method is used for returning the list of interfaces that are provided by an object. |
| list(zope.interface.providedBy(class)) | This method returns an empty list since a class does not provide an interface but implements it. |
To understand these methods and how does it work, let's take an example.
import zope.interface;
#making the test interface
class TestInterface(zope.interface.Interface):
y = zope.interface.Attribute("foo")
# method one
def methodName1(self, y):
pass
# method two
def methodName2(self):
pass
# method implementer
@zope.interface.implementer(TestInterface)
class TestClass:
def methodName1(self, y):
return y**2
def methodName2(self):
return "hello"
obj = TestClass()
# this obj is used for returning a boolean value by checking the condition, if the test class implements the interface, then it returns true, else it returns false.
print(TestInterface.implementedBy(TestClass))
# this obj returns a boolean value, if the object provides an interface then it returns true, else false.
print(TestInterface.providedBy(TestClass))
# It returns a boolean value, if the object provides an interface then it returns true, else false.
print(TestInterface.providedBy(obj))
# It is used for returning a boolean value, if the class implements the interface, then it returns true, else it returns false.
print(list(zope.interface.implementedBy(TestClass)))
# It returns a boolean value, if the object provides an interface then it returns true, else false.
print(list(zope.interface.providedBy(obj)))
# It returns a boolean value, if the object provides an interface then it returns true, else false.
print(list(zope.interface.providedBy(TestClass)))
Output:
True
False
True
[<InterfaceClass __main__.TestInterface>]
[<InterfaceClass __main__.TestInterface>]
There are two types of interface in python:
Formal interface
Informal interface
These are mainly used for larger and more complex applications whereas the informal interface is used by relatively smaller applications that have a limited set of people.
In order to create a formal interface in python, tools from abc modules will be used.
For enforcing the instantiation of a subclass of the abstract methods, python's built-in library ABCMeta will be used from the module named abc. In this, instead of creating your own metaclass, we will use the metaclass provided by abc.ABCMeta. We can then override the methods of the metaclass. For instance, we can overwrite .subclasshook() in place of .instancecheck() and .subclasscheck()since these provide a more efficient implementation of the methods.
Once the abc module is imported, we can directly register a class that is virtual by using the metamethod .register().
Run the following example in your code editor:
class Double(metaclass=abc.ABCMeta):
"""Double precision floating point number."""
pass
Double.register(float)
The effect of .register() function can be checked on the cmd as follows:
>>> issubclass(float, Double)
True
>>> isinstance(1.2345, Double)
True
When combining .subclasshook() with .register() we must take care since .subclasshook() has higher precedence as compare to virtual subclass registration. In order to ensure that the virtual subclass is taken into consideration, NotImplemented must be added to .subclasshook() method.
Look at the example given below to understand this better.
class FormalParserInterface(metaclass=abc.ABCMeta):
@classmethod
def __subclasshook__(cls, subclass):
return (hasattr(subclass, 'load_data_source') and
callable(subclass.load_data_source) and
hasattr(subclass, 'extract_text') and
callable(subclass.extract_text) or
NotImplemented)
class PdfParserTest:
"""This is used for Extracting text from a PDF."""
def load_data_source(self, path: str, file_name: str) -> str:
"""Overrides FormalParserInterface.load_data_source()"""
pass
def extract_text(self, full_file_path: str) -> dict:
"""Overrides FormalParserInterface.extract_text()"""
pass
@FormalParserInterface.register
class EmlParserTest:
"""Extract text from an email."""
def load_data_source(self, path: str, file_name: str) -> str:
"""Overrides FormalParserInterface.load_data_source()"""
pass
def extract_text_from_email(self, full_file_path: str) -> dict:
"""A method defined only in EmlParser.
Does not override FormalParserInterface.extract_text()
"""
pass
print(issubclass(PdfParserTest, FormalParserInterface)) # it returns True
print(issubclass(EmlParserTest, FormalParserInterface)) # it returns True
The method that is declared by the interface of python but does not has any useful implementation in the application is called as an abstract method.
This method must be overridden by a class that is concrete and that implements the interface. In order to create the abstract method in python, we just have to add @abc.abstract method decorator to the method’s interface.
There might be situations or events where strict rules that is present in a formal python interface are not needed. This is where the informal interface comes into the picture.
The informal interface in python is a class that is used for defining the methods that can be overridden but have no strict enforcement. The informal interface can be implemented by using the following classes.
We would ideally want the issubclass(EmlParser, InformalParserInterface) to return false when the class that is implemented does not define all the abstract methods of the interface. For doing this, we can create a metaclass called as ParserMeta and can override the following two methods:
.instancecheck()
.subclasscheck()
In order to understand his much better, look at the code example given below:
class ParserMeta(type):
"""A Parser metaclass that will be used for parser class creation.
"""
def __instancecheck__(cls, instance):
return cls.__subclasscheck__(type(instance))
def __subclasscheck__(cls, subclass):
return (hasattr(subclass, 'load_data_source') and
callable(subclass.load_data_source) and
hasattr(subclass, 'extract_text') and
callable(subclass.extract_text))
class UpdatedInformalParserInterface(metaclass=ParserMeta):
"""This interface is used for concrete classes to inherit from.
There is no need to define the ParserMeta methods as any class
as they are implicitly made available via .__subclasscheck__().
"""
pass
The virtual base class method is used for checking if .subclasscheck() is a virtual class of the superclass.
Let's take an example given below to understand this example better:
# Inheriting subclasses
class Employee(PersonSuper):
"""Inherits from PersonSuper
PersonSuper will appear in Employee.__mro__
"""
pass
class Friend:
"""Built implicitly from Person
Friend is a virtual subclass of Person since
both required methods exist.
Person not in Friend.__mro__
"""
def name(self):
pass
def age(self):
pass
Here we have created a setup for creating a virtual base class for
The metaclass is PersonMeta
The base class is PersonSuper
The python interface which is python
In this example, the employee class inherits from the PersonSuper while the Friend class inherits from the Person class.
The Friend class, however, does not explicitly inherit from the Person class but it implements the .name() and the .age(), and hence the Person becomes a virtual base class of the Friend class. The diagram shown below depicts the concept more clearly.