Callbacks¶
Callbacks provide an interface to register other callbacks, that will be called back when the
Callback
object is called.
A Callback
is similar to holding a pointer to a function, except it supports multiple functions.
Example:
class Data:
def __init__(self, x: int) -> None:
self._x = x
self.on_changed = Callback()
@property
def x(self) -> int:
return self._x
@x.setter
def x(self, x: int) -> None:
self._x = x
self.on_changed(x)
In the code above, Data
contains a x
property, which triggers a on_changed
callback
whenever x
changes.
We can be notified whenever x
changes by registering a function in the callback:
def on_x(x: int) -> None:
print(f"x changed to {x}")
data = Data(10)
data.on_changed.Register(on_x)
data.x = 20
The code above will print x changed to 20
, because changing data.x
triggers all functions
registered in data.on_changed
.
An important feature is that the functions connected to the callback are weakly referenced, so methods connected to a callback won’t keep the method instance alive due to the connection.
We can unregister functions using Unregister
, check if a function
is registered with Contains
, and unregister all connected functions
with UnregisterAll
.
Type Checking¶
New in version 1.1.0.
oop-ext
also provides type-checked variants, Callback0
, Callback1
, Callback2
, etc,
which explicitly declare the number of arguments and types of the parameters supported by
the callback.
Example:
class Point:
def __init__(self, x: float, y: float) -> None:
self._x = x
self._y = y
self.on_changed = Callback2[float, float]()
def update(self, x: float, y: float) -> None:
self._x = x
self._y = y
self.on_changed(x, y)
def on_point_changed(x: float, y: float) -> None:
print(f"point changed: ({x}, {y})")
p = Point(0.0, 0.0)
p.on_changed.Register(on_point_changed)
p.update(100.0, 2.5)
In the example above, both the calls self.on_changed
and on_changed.Register
are properly
type checked for number of arguments and types.
The method specialized signatures are only seen by the type checker, so using one of the specialized variants should have nearly zero runtime cost (only the cost of an empty subclass).
Note
The separate callback classes are needed for now, but if/when
pep-0646 lands, we should be able to
implement the generic variants into Callback
itself.