Creating Reactive Functions
Creating Reactive Functions¶
Meerkat provides the
@mk.reactive() decorator to designate a function as reactive. If you haven’t used Python decorators before, they are simply wrappers around a function. When we use
@mk.reactive(), the decorator will return a new function that is reactive.
mk.reactive(), use standard Python syntax for decorators. There are three ways to do this:
Decorate a function with
@mk.reactive() def add_by_1(a): return a + 1
mk.reactive()on a function:
def add_by_1(a): return a + 1 add_by_1 = mk.reactive(add_by_1)
mk.reactive()on a lambda function:
add_by_1 = mk.reactive(lambda a: a + 1)
All three methods have the same effect of creating a reactive function called
add_by_1 that can be used in subsequent lines of code.
What does wrapping a function with
mk.reactive() actually do?
At a high level, these functions will be rerun when their inputs change.
We’ll look at this in more detail in a bit. First, though, we’ll talk about
Markable objects, which are intertwined with reactive functions.
Demystifying Reactive Functions¶
Now that we understand the importance of
Store objects to reactivity, let’s look at how reactive functions work. Consider the same function
What happens when you wrap
@mk.reactive() def add(a, b): return a + b
Meerkat tracks the function
add and reruns it if any of the inputs to it (i.e.,
b) change. Here, we are assuming that both
b are marked. Internally, Meerkat puts the
add function into a computation graph that tracks dependencies between reactive functions.
What happens when you call
x = mk.Store(1) y = mk.Store(2) z = add(x, y) # z is Store(3), type(z) is Store
Meerkat does the following steps:
Unwrap input stores. Any inputs to
Storeobjects are unwrapped before passing them into the body of
Turn off reactivity. Meerkat turns off reactivity before executing the function. This only applies for the duration of the function call.
Execute the function. The function is executed as if it were a normal Python function.
Wrap and mark the outputs: Then, the output of
addis wrapped in a
Storeobject and returned. If the output is a markable object (e.g.,
mk.DataFrame <meerkat.DataFrame>), the object is marked. This lets us use the output of
addas input to other reactive functions.
Turn on reactivity: Meerkat turns reactivity back on once the function has returned.
The main consequence of these steps is that any reactive function can be written as a regular Python function. We don’t have to worry about unwrapping
Store inputs or managing reactivity manually. Thus, we can convert any existing Python function into a reactive function simply by wrapping it with
What happens when you change any of the inputs to
x = mk.Store(1) y = mk.Store(2) z = add(x, y) # z is Store(3), type(z) is Store x.set(4, triggers=True) # z is now Store(6), type(z) is Store
What does Meerkat do when
x is changed? Let’s walk through the steps:
Meerkat detects that
.set()was called on it.
Meerkat looks for all reactive functions that were called with
xas an argument (i.e.
Meerkat then reruns those functions (i.e.,
add) and any functions that depend on their outputs.
Finally, Meerkat updates the outputs of any reactive functions that it reruns (i.e.
What happens when reactive function doesnt have arguments
Using the same reactive function multiple times