Implement Interface in Python

Steve Langford·2022년 11월 16일

coding

목록 보기
1/2

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.

Overview

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.

Declaring the Interface in Python

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

The Methods of the Interface in Python

There are several methods provided by the class interface in python, a few of which are as follows:

Method nameDescription
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>]

Types of Interface in Python

There are two types of interface in python:

Formal interface
Informal interface

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

Using abc.ABCMeta

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.

Using abc to Register a Virtual Subclass

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

Using Subclass Detection With Registration

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

Code reference

Using Abstract Method Declaration

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.

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

Using Metaclasses

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

Using Virtual Base Classes

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.

0개의 댓글