Will this trick to collect parameter dependencies cause me unexpected trouble?

I’ve realised that you can use dummy methods to collect and re-use parameter dependencies, and also define a kind of recursive dependency (see example below). I haven’t seen this use of the ‘depend-on-method’ feature mentioned in the docs or sample code that I’ve read.

Two questions:

  1. Can anyone think of ways this trick might cause me some kind of problems in the future?
  2. Is there a less hacky, officially sanctioned way to do this?
import param


class Foo(param.Parameterized):
    a = param.Parameter()
    b = param.Parameter()
    c = param.Parameter()
    d = param.Parameter()
    e = param.Parameter()

    def _all_params(self):  # this method depends on all params!
        pass

    @param.depends("a", "e")
    def _vowels(self):
        pass

    @param.depends("b", "c", "d")
    def _consonants(self):
        pass

    @param.depends("a._vowels", "a._sub_vowels_a")
    def _sub_vowels_a(self):
        pass

    @param.depends("_all_params")
    def method1(self):
        pass

    @param.depends("_vowels")
    def method2(self):
        pass

    @param.depends("_consonants")
    def method3(self):
        pass

    @param.depends("_vowels", "_consonants")
    def method4(self):
        pass

    @param.depends("_sub_vowels_a")
    def method5(self):
        pass


foo = Foo(name="outer", a=Foo(name="inner", a=Foo(name="innermost")))
for m in ["method1", "method2", "method3", "method4", "method5"]:
    print(m)
    dependencies = foo.param.method_dependencies(m)
    print([f"{o.inst.name}.{o.pobj.name}:{o.what}" for o in dependencies])
method1
['outer.name:value', 'outer.a:value', 'outer.b:value', 'outer.c:value', 'outer.d:value', 'outer.e:value']
method2
['outer.a:value', 'outer.e:value']
method3
['outer.b:value', 'outer.c:value', 'outer.d:value']
method4
['outer.a:value', 'outer.e:value', 'outer.b:value', 'outer.c:value', 'outer.d:value']
method5
['inner.a:value', 'inner.e:value', 'innermost.a:value', 'innermost.e:value']

Param’s documentation says that you can depend on a method name:

Dependencies on a method name: Often you will want to break up computation into multiple chunks, some of which are useful on their own and some which require other computations to have been done as prerequisites. In this case, your method can declare a dependency on another method (as a string name), which means that it will now watch everything that method watches, and will then get invoked after that method is invoked.

Sorry, I wasn’t clear enough in my OP. I’m aware that the ‘depend-on-method’ feature exists and is documented. What I am wondering about is the use of dummy methods to bundle frequently used sets of parameter dependencies together, and defining recursive dependencies through layers of subobjects. Is this pattern dis/encouraged?

Ahah, I have found a case where doing this results in unintuitive (possibly bugged?) behaviour:

import param

class Parent(param.Parameterized):
    a = param.Parameter()

    def _all(self): # dummy function that depends on all params
        pass
    
    @param.depends('_all', watch=True)
    def foo(self):
        print('foo called')

class Child(Parent):
    b = param.Parameter()

c = Child(a=1, b=2)

for p in c.param.method_dependencies('foo'):
    print(p.name) # I get a list of all the parameters, as desired
# name
# a
# b

c.a +=1
# foo called

c.b +=1 # foo does not get called

So it seems that even though the parameter b of the child class is registered to the method dependencies, it is not actually being watched in the way that parameter a of the parent class is.

1 Like