import param as pm
class B(pm.Parameterized):
class A(pm.Parameterized):
a = pm.Integer(10)
b = pm.Number(0)
a = A()
b = pm.Integer(50)
def __init__(self, **params):
super().__init__(**params)
@pm.depends("a.a", watch=True)
def callback(self):
print(self.a.a * 10)
Second approach:
- as Class Selector
import param as pm
class B(pm.Parameterized):
class A(pm.Parameterized):
a = pm.Integer(10)
b = pm.Number(0)
a = pm.ClassSelector(class_=A, default=A())
b = pm.Integer(50)
def __init__(self, **params):
super().__init__(**params)
@pm.depends("a.param", watch=True)
def callback(self):
print(self.a.a * 10)
Maybe there are another approaches?
What difference between them?
I’ve would do something close to your second approach.
import param as pm
class X(pm.Parameterized):
a = pm.Integer(10)
b = pm.Number(0)
class Y(pm.Parameterized):
c = pm.ClassSelector(class_=X)
d = pm.Integer(50)
def __init__(self, **params):
if not "c" in params:
params["c"]=X()
super().__init__(**params)
@pm.depends("c.param", watch=True)
def callback(self):
self.d+=1
print("c", self.c.a, self.c.b)
print("d", self.d)
If I add the test_case below to the script
def test_case():
y=Y()
for _ in range(0,2):
y.c.a+=1
y.c.b+=1
test_case()
I am currently working on a project where some graphical styling properties can be set by a user. So far I implemented a bunch of classes with setters and getters with some validation. It works but its is very verbose and with the param library I was hoping to make the code cleaner and later make the step to implement the parametrization via some GUI much simpler.
Well I think that the .update method doesn’t allow you to update nested Parameters like that. It may be worthwhile opening a feature request (if there isn’t one already!) to see what the core devs think about it.
In the mean time you could try to use this function that takes a parameterized object and a nested dict and update each one of the parameters declared in the nested dict:
def update_with_nested_dict(parameterized, nested_dict):
# Using `batch_call_watchers` because it has the same underlying
# mechanism as with `param.update`
# See https://param.holoviz.org/user_guide/Dependencies_and_Watchers.html?highlight=batch_call#batch-call-watchers
with param.parameterized.batch_call_watchers(parameterized):
for pname, value in nested_dict.items():
if isinstance(getattr(parameterized, pname), param.Parameterized):
if not isinstance(value, dict):
raise ValueError(
f'The nested parameterized parameter "{pname}" must be '
f'updated with a dictionary, not a {type(value).__name__}.')
update_with_nested_dict(getattr(parameterized, pname), value)
else:
setattr(parameterized, pname, value)
And use it as follows:
update_with_nested_dict(bs, new_values)
I’ve just tried this function quickly on a simple example and it worked, but Param is a complex machinery so if you use that function in your code try to make sure it works as you expect.