I have one large class that computes ~50 different metrics (each metric has no side effects).
My code is similar to this:
class ReportingMetrics: def __init__(self, data:pd.DataFrame, config:dict): self.data = data ... # Common data validation, etc... def calculate_metric1(self)->pd.Series: ... def calculate_metric2(self)->pd.Series: ... def calculate_metric3(self)->pd.Series: ... def calculate_metric4(self)->pd.Series: ... def calculate_metric5(self)->pd.Series: ... def calculate_metric6(self)->pd.Series: ... ... And as you can imagine, I add metrics fairly often.
I am considering a refactor where each calculate_metric{i} is either a function or a class - and they get "registered" to a data structure of some kind.
It would look something like:
class BaseReportingMetric: @abstractmethod def calculate(self)->pd.Series: ... class ReportingMetric1(BaseReportingMetric): ... class ReportingMetric2(BaseReportingMetric): ... reporting_metric_register = [ ReportingMetric1, ReportingMetric2, ... ] I've also seen a common pattern where the BaseReportingMetric class implements a .register(self, reporting_metric_register) if I want to keep the registering/unregistering as part of the metric code.
However, doing this would be a fairly large refactor, so happy to hear of good/bad experiences from people that have changed their code from one style to the other.