Callback#
Callback is a philosophy that is commonly used in LEADS. Some come in the form of callback objects, while others come in the form of single functions. This article only discusses the former, which are more common. If you encounter the latter, they are usually explained in the specific usage.
Callback Chain#
Registration of a callback is generally not a replacement. A newly registered callback is usually added as a new node to the callback chain. This callback chain is similar to a linked list.
LEADS implements this fundamental structure as CallbackChain. It provides the
capability to be bound to another CallbackChain. It should be used as a template
only. The following example defines a specific callback class and a use case.
from leads import CallbackChain
class MyCallback(CallbackChain):
def on_my_callback_is_called(self, name: str) -> None:
...
class MyBusiness(object):
def __init__(self) -> None:
self._callback: MyCallback | None = None
def set_callback(self, callback: MyCallback) -> None:
callback.bind_chain(self._callback)
self._callback = callback
def do_something(self, name: str) -> None:
if self._callback:
self._callback.on_my_callback_is_called(name)
Now, the user can pass its callback object to the business.
from typing import override
from leads import CallbackChain, L
class MyCallback(CallbackChain):
def on_my_callback_is_called(self, name: str) -> None:
...
class MyBusiness(object):
def __init__(self) -> None:
self._callback: MyCallback | None = None
def set_callback(self, callback: MyCallback) -> None:
callback.bind_chain(self._callback)
self._callback = callback
def do_something(self, name: str) -> None:
if self._callback:
self._callback.on_my_callback_is_called(name)
class UserCallbackA(MyCallback):
@override
def on_my_callback_is_called(self, name: str) -> None:
self.super(name=name)
L.info(f"My callback is called with an argument name={name}")
if __name__ == "__main__":
my_business = MyBusiness()
my_business.set_callback(UserCallbackA())
my_business.do_something("test_case_1")
Important
It is advised to always call super() unless you want to override all previously
declared methods.
Now suppose another user wants to register another callback object from somewhere else.
from typing import override
from leads import CallbackChain, L
class MyCallback(CallbackChain):
def on_my_callback_is_called(self, name: str) -> None:
...
class MyBusiness(object):
def __init__(self) -> None:
self._callback: MyCallback | None = None
def set_callback(self, callback: MyCallback) -> None:
callback.bind_chain(self._callback)
self._callback = callback
def do_something(self, name: str) -> None:
if self._callback:
self._callback.on_my_callback_is_called(name)
class UserCallbackA(MyCallback):
@override
def on_my_callback_is_called(self, name: str) -> None:
self.super(name=name)
L.info(f"My callback is called with an argument name={name}")
class UserCallbackB(MyCallback):
@override
def on_my_callback_is_called(self, name: str) -> None:
self.super(name=name)
L.info(f"User B's callback is called with an argument name={name}")
if __name__ == "__main__":
my_business = MyBusiness()
my_business.set_callback(UserCallbackA())
my_business.set_callback(UserCallbackB())
my_business.do_something("test_case_2")
The output should be printing both “My callback is called with an argument name=test_case_2” and “User B’s callback is called with an argument name=test_case_2”.
Existing Callback Classes#
The two main callback classes are EventListener and
Callback.