How does param.Action/Callable handle passing self to function? Unexpected behavior in conjunction with Panel

I’m working on building a Parameterized class for driving a Panel application. I’ve included a simplified version of my code for the sake of clarity.

Below, Panel in conjunction with Param is working as expected.
(Although I’m not sure WHY self can be passed into an action - I believe I stumbled upon this through experimentation and not documentation.
url_input stores the "Testing" string, Panel creates the button which is bound to a function which appends that to the url_list. When pressed it works as expected and populates the ee.url_list attribute.

class ExpEnv(param.Parameterized):
  url_input = param.String()
  url_list = param.List([])
  url_submit = param.Action(lambda self: self.url_list.append(self.url_input))

ee = ExpEnv()

image

However, if I try to programmatically hit submit, I get an error saying that self is missing.

ee.url_input = "Testing"
ee.url_submit()

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[69], line 2
      1 ee.url_input = \"Testing\"
----> 2 ee.url_submit()

TypeError: ExpEnv.<lambda>() missing 1 required positional argument: 'self'"

I’m not certain why this is happening, or how I can programmatically call url_submit.

Edit: Forgot to mention that ee.url_submit(ee) does work - although it does make my sensibilities bleed.

Panel treats the Action Parameter in a special way, registering a callback on a button click that expects to be passed the Parameterized instance (self.object in the code below, value being the callback function).

Forgot to mention that ee.url_submit(ee) does work - although it does make my sensibilities bleed.

I don’t like that either, I’d probably choose a more verbose approach like:

class ExpEnv(param.Parameterized):
    url_input = param.String()
    url_list = param.List([])
    url_submit = param.Event()

    @param.depends('url_submit', watch=True)
    def append_url_list(self):
        self.url_list.append(self.url_input)
        
ee = ExpEnv()
pn.Param(ee)
1 Like

Appreciate the Panel snippet, that does confirm the usage pattern of passing the instance to the Action(that exists within the instance itself :exploding_head:).

It’s just a bit counter-intuitive to me as to why Action wouldn’t by default be passed the instance.
Especially when the documentation itself states:

Invocation parameters are a loose group of types that either contain an executable (callable) object, are invoked to execute some other code, or are set to change the value of some other parameter(s) or attribute(s).

Yes you’re right, the docs from Parameter types — param v2.0.1 aren’t well aligned with the reality. The bit on Action says that it is expected to have no arguments, while Panel requires the Action callable to have the instance as an argument.

@dleybel do you mind opening an issue on GitHub - holoviz/param: Param: Make your Python code clearer and more reliable by declaring Parameters to highlight this problem, referencing this discussion on Discourse?


Invocations

  • param.Callable: A callable object, such as a function
  • param.Action: A callable with no arguments, ready to invoke
  • param.Event: Empty action, for use in triggering events for watchers
  • param.Composite: Wrapper around other parameters, letting them be set as a tuple

Invocation parameters are a loose group of types that either contain an executable (callable) object, are invoked to execute some other code, or are set to change the value of some other parameter(s) or attribute(s).

A Callable may be set to any callable object, typically either a function or else an instance of a class that provides a __call__ method. At present, there is no validation that the provided callable takes any particular number or type of arguments. Lambdas can be provided, but note that the resulting parameter value will no longer be picklable, so if you need to use pickling (setstate and getstate), be sure to use a named function instead.

An Action is the same as a Callable, but is expected to have no arguments. In a GUI an Action is typically mapped to a button whose name or label is the name of this parameter.


Opened the issue: Cannot change class attributes with a Callable without passing in parametrized class, creating a poor interface and confusion. · Issue #900 · holoviz/param · GitHub

Would’ve done it sooner if Discourse decided to notify me of posts.