Watching changes in attribute of attribute

I’ve got a parameterized class that’s nested in a parameterized class, and I’d like to listen to changes in an attribute of that nested class. Basically in the MWE below, when I change foo I’d like the Markdown pane to update. Of course I can’t directly listen to foo as that’s not a parameter on B.
I’ve toyed around a bit with various variations on the below but to no avail. Does anyone have an idea? Thanks!

import param
import panel as pn
pn.extension()

class A(param.Parameterized):
    foo = param.Integer()
    
class B(param.Parameterized):
    a = param.ClassSelector(A)
    bar = param.Integer()
    
class Viewer(B):
    @param.depends('a', 'bar')
    def controls(self):
        return pn.Param(self.a, parameters=['foo'])
    
    @param.depends('a', 'bar')
    def view(self):
        return pn.pane.Markdown(f'Sum: {self.a.foo+self.bar+2}')
    
a = A()
v = Viewer(a=a)
pn.Row(v.controls, v.view)
1 Like

E.g. something like the below seems to trigger the update in A but still nothing happens in B:

import param
import copy

class A(param.Parameterized):
    foo = param.Integer()
    
class B(param.Parameterized):
    a = param.ClassSelector(A)
    bar = param.Integer()
    
class TriggerA(A):
    @param.depends('foo', watch=True)
    def _update(self):
        print('Updating...')
        self = copy.copy(self)
    
class Viewer(B):
    @param.depends('a', 'bar', watch=True)
    def controls(self):
        return pn.Param(self.a, parameters=['foo'])
    
    @param.depends('a', 'bar', watch=True)
    def view(self):
        return pn.pane.Markdown(f'Sum: {self.a.foo+self.bar+2}')
    
a = TriggerA()
v = Viewer(a=a)
pn.Row(v.controls, v.view)

Listening to ‘a’ will only trigger updates when the entire object is swapped out but you can listen to specific parameters on the sub-object by using the ‘parameterized.parameter’ syntax, e.g. in your case that would be:

    @param.depends('a.foo', 'bar')
    def view(self):
        return pn.pane.Markdown(f'Sum: {self.a.foo+self.bar+2}')

As an aside, do not use watch=True on a function which returns something like in your second example. This will start warning in the next release.

1 Like

Thanks, also for the watch=True heads up!

1 Like