The singleton scheme is similar to the subclass one
with the exception: Loader returns plugin instance, rather than class.
Instance is initialized on the first load, and only one instance of plugin
exists.
We need the base class to define the scheme, then inherit the plugins.
fromabcimportABC,abstractmethodclassBasePlugin(ABC):"""Base class for our plugin."""@abstractmethoddefexecute(self,x:int,y:int)->int:"""Plugin performs operation on two integers and returns integer."""
fromabcimportABC,abstractmethodclassBasePlugin(ABC):"""Base class for our plugin."""@abstractmethoddefexecute(self,x:int,y:int)->int:"""Plugin performs operation on two integers and returns integer."""
In this module, we define an abstract class. It does not provide an actual implementation
but rather specifies an interface. The established practice in Python is to derive
such classes from ABC and mark the required parts with @abstractmethod.
fromabcimportABC,abstractmethodclassBasePlugin(ABC):"""Base class for our plugin."""@abstractmethoddefexecute(self,x:int,y:int)->int:"""Plugin performs operation on two integers and returns integer."""
Define a base class for our plugins. We have no particular requirements,
so we can derive it from ABC to mark this class is abstract.
fromabcimportABC,abstractmethodclassBasePlugin(ABC):"""Base class for our plugin."""@abstractmethoddefexecute(self,x:int,y:int)->int:"""Plugin performs operation on two integers and returns integer."""
Though docstrings are advisory, it will help to navigate our code,
so describe plugin tasks and features.
fromabcimportABC,abstractmethodclassBasePlugin(ABC):"""Base class for our plugin."""@abstractmethoddefexecute(self,x:int,y:int)->int:"""Plugin performs operation on two integers and returns integer."""
The @abstractmethod decorator indicates that a method must be implemented in derived classes.
fromabcimportABC,abstractmethodclassBasePlugin(ABC):"""Base class for our plugin."""@abstractmethoddefexecute(self,x:int,y:int)->int:"""Plugin performs operation on two integers and returns integer."""
Our main function of the plugin, do not to forget to place the proper type hints to allow
static type checking.
fromabcimportABC,abstractmethodclassBasePlugin(ABC):"""Base class for our plugin."""@abstractmethoddefexecute(self,x:int,y:int)->int:"""Plugin performs operation on two integers and returns integer."""
The main function of the plugin already should be documented.
Then let's create a loader instance. You need only one loader instance per each type for your application. So loaders are usually singletons.
Loader is the generic type, so we must pass the exact plugin type. The instances of
BasePlugin type has the BasePlugin type. We'd placed the type into
the brackets just after the Loader.
After defining the plugin's type, we need to initialize the loader itself.
Loader has several initialization parameters, see Reference
for details. Here we consider our plugins will be in plugins folder of our applications.
Loader supports dict-like interface to access the modules. For this example, we will
use bracket notation. We use op parameter as the plugin name. Unlike the
subclass scheme, our loader returns the initialized instance directly.