Make param.depends efficient
- Dominant language
- Python
- Stars
- 521
- Forks
- 86
- Avg merge
- 1d 13h
- Merged PRs (30d)
- 35
Description
Its becoming more and more clear to me just how inefficient param.depends and param.bind are if you want to depend on them multiple times.
Thus I suggested at HoloViz meeting that for Panel that we start recommending `pn.rx(some_func)(args,...)` over `pn.bind(some_func, args...)` because the end usage is the same. But the pn.rx version is much more efficient. But the feedback was that `pn.rx` was not yet well enough understood.
As an alternative I would suggest making `pn.depends` (and `pn.bind`) more efficient by caching results similar to what `pn.rx` does.
One more argument is that Panel tutorials promotes creating more advanced applications with the DataStore design pattern. And this also promotes depending multiple times on references. The tutorial uses `pn.rx`. I don't know if Philipp did it for efficiency reasons or just because he could? But using `param.depends` without `watch=True` would have led to an inefficient application https://panel.holoviz.org/tutorials/intermediate/structure_data_store.html.
## Example
The below example shows how inefficient it is to depend on a `param.depends` annotated function multiple times.
https://github.com/holoviz/param/assets/42288570/c814b45f-d3e7-419f-8392-6c2e89930c4e
```python
import param
import panel as pn
pn.extension()
slider = pn.widgets.IntSlider(value=0, start=1, end=2)
class Model(param.Parameterized):
value = param.Integer(default=1, bounds=(1,10))
count = param.Integer(default=0)
@param.depends("value")
def result(self):
self.count+=1
return self.value
@param.depends("result")
def other_result(self):
return self.result()
class Model2(param.Parameterized):
value = param.Integer(default=1, bounds=(1,10))
result = param.Integer()
other_result = param.Integer()
count = param.Integer(default=0)
@param.depends("value", watch=True)
def _update_result(self):
self.count+=1
self.result = self.value
@param.depends("result", watch=True)
def _update_other_result(self):
self.other_result= self.result
model = Model()
model2 = Model2()
pn.Row(
pn.Column(model.param.value, model.param.count, model.result, model.other_result),
pn.Column(model2.param.value, model2.param.count, pn.pane.Str(model2.param.result), pn.pane.Str(model2.param.other_result))
).servable()
```
As you can see, you can avoid the inefficiency by using `watch=True` and updating named parameters. But this makes your code much longer and much more complicated.
Contributor guide
Assessment
This issue has not been assessed yet.