Class-based Panel app using Param with customized formatters

Hello, I have the following app built using panel that is an example of functional programming:

from bokeh.models.widgets.tables import NumberFormatter, StringFormatter
import intake
import pandas as pd
import panel as pn

pn.extension("tabulator")

url = "https://url/for/intake_catalog.yml"
cat = intake.open_catalog(url)

# access tutorial catalog
sub_cat= cat["sub_cat"]

# get list of datasets for descriptive statistics
datasets = [dataset for dataset in list(sub_cat) if "desc" in dataset]

dataset_select = pn.widgets.Select(
    description = "Select a Dataset",
    name="Dataset",
    options=datasets
)

@pn.cache(per_session=True)
def _get_data(_dataset: str, _catalog: intake.Catalog = sub_cat) -> pd.DataFrame:
    """Reaches and caches data from intake catalog."""

    return _catalog[_dataset].read()


def _get_description(_dataset: str, _catalog:intake.Catalog = sub_cat) -> str:
    """Returns description of dataset."""

    _description = _catalog[_dataset].description

    return _description

def create_bokeh_formatters(column_dict: dict) -> dict:
    """Create a dynamic list of formatted columns."""

    formatters = {}

    for column, dtype in column_dict.items():
        if dtype == "float":
            formatters[column] = NumberFormatter(format="0.00")
        if dtype == "str":
            formatters[column] = StringFormatter()

    return formatters

@pn.depends(dataset_select)
def construct_tabulator(dataset: str, catalog:intake.Catalog = sub_cat) -> pd.DataFrame:
    """Create tabulator object based on changes to selected dataset."""

    # create dataframe
    _df = _get_data(dataset)

    # create column formatters
    _column_formatters = create_bokeh_formatters(_df.dtypes.to_dict())

    _df_tabulator = pn.widgets.Tabulator(_df, 
                                  name="Tabulator",
                                  hidden_columns=["index"],
                                  disabled=True,
                                  theme="modern",
                                  formatters=_column_formatters
                                  )
    
    # get description for each dataset and render as html h2
    _df_description = _get_description(dataset)

    _description_display = pn.pane.Markdown(f"## {_df_description}")

    # create a column
    _df_display = pn.Column(_description_display, _df_tabulator)
    
    return _df_display


pn.Column(dataset_select,
        construct_tabulator
          ).servable()

This works great but when I try to create a more OOB Class based implementation, my app stops functioning when I add the create_bokeh_formatters.

from bokeh.models.widgets.tables import NumberFormatter, StringFormatter
import intake
import pandas as pd
import panel as pn
import param
pn.extension("tabulator")

# intake catalog setup
url = "https://url/for/intake_catalog.yml"
cat = intake.open_catalog(url)

# access tutorial catalog
sub_cat= cat["sub_cat"]

# get list of datasets for descriptive statistics
datasets = [dataset for dataset in list(sub_cat) if "desc" in dataset]

# get data from catalog
def _get_data(_dataset: str, _catalog:intake.Catalog = sub_cat) -> pd.DataFrame:
    return _catalog[_dataset].read()

def create_bokeh_formatters(column_dict: dict) -> dict:
    """Create a dynamic list of formatted columns."""

    formatters = {}

    for column, dtype in column_dict.items():
        if dtype == "float":
            formatters[column] = NumberFormatter(format="0.00")
        if dtype == "str":
            formatters[column] = StringFormatter()

    return formatters

df_dtypes = {}
class DescTabulator(param.Parameterized):
    dataset = param.Selector(objects=datasets)
    dataframe = param.DataFrame(sub_cat[datasets[0]].read())

    @param.depends("dataset", watch=True)
    def _update_dataframe(self):
        df = sub_cat[self.dataset].read()
        globals()["df_dtypes"] = df.dtypes.to_dict()
        self.dataframe = df

tab = DescTabulator()

tab_panel = pn.Param(tab, widgets={
    "dataframe": dict(widget_type=pn.widgets.Tabulator, 
                      hidden_columns=["index"], 
                      formatters=create_bokeh_formatters(df_dtypes) # commenting out this line allows the app 
                                                                    # to update when a different dataset is collection
                      )
})

pn.Row(tab_panel).servable()

I was wondering if anyone has been able to custom format a Tabular using pn. Param? Thanks!