Create independent class instances using ClassSelector parameter

I’m trying to create a parameterized class with a ClassSelector parameter that will allow a user in a panel GUI to select a class. The user could then click a button that would call a function that creates an instance of the selected class and adds it to a list.

Here is a toy example.

class Animals(param.Parameterized):
    weight = param.Number()
    
class Lion(Animals):
    color = param.String(default='yellow')

class Bear(Animals):
    color = param.String(default='brown')

class ListOfClassInstances(param.Parameterized):
    instance_list = param.List(precedence=-1)
    current_class = param.ClassSelector(
        class_=Animals,
        is_instance=False,
        per_instance=True,
        instantiate=True
    )
    def add_animal(self, event):
        self.instance_list.append(copy.deepcopy(self.current_class))
    def reset_instance_list(self, event):
        self.instance_list = []

l = ListOfClassInstances()

class_selector_widget = pn.Param(
    l.param, widgets={
        'current_class': pn.widgets.Select,
    }
)

add_animal_button = pn.widgets.Button(name='Add animal', button_type='primary')
add_animal_button.on_click(l.add_animal)

reset_list_button = pn.widgets.Button(name='Reset list', button_type='primary')
reset_list_button.on_click(l.reset_instance_list)

pn.Row(class_selector_widget, pn.Column(add_animal_button, reset_list_button))

If I select the Bear class and then click the “Add Animal” button twice, then the instance_list parameter does contain two instances of ParamterizedMetaclass. It seems like the object in the instance_list are pointing at the same object in memory, so I’m not able to change the parameters of one of them to different values. I would like to be able to change the color of the first item in the list to ‘red’ without that affecting the color of the second item in the list.

Is there a better or more direct way to get the select widget as well? The param docs, state “In a GUI, the range list allows a user to select a type of object they want to create, and they can then separately edit the new object’s parameters (if any) to configure it appropriately.”, which seem like what I am trying to do. Should I use get_range() somehow?

Hey @bt-1 !

Wouldn’t that work for you?

class Animals(param.Parameterized):
    weight = param.Number()
    
class Lion(Animals):
    color = param.String(default='yellow')

class Bear(Animals):
    color = param.String(default='brown')

class ListOfClassInstances(param.Parameterized):
    instance_list = param.List(precedence=-1)
    current_class = param.ClassSelector(
        class_=Animals,
        is_instance=False,
    )
    def add_animal(self, event):
#         self.instance_list.append(copy.deepcopy(self.current_class))
        self.instance_list.append(self.current_class())
    def reset_instance_list(self, event):
        self.instance_list = []

l = ListOfClassInstances()

@maximlt, yes that fixes it! I thought it seemed harder than it should. Thank you!