I am working with a large Python class with dozens of "business logic" methods and a few helper methods. There is some funny code at the end that is being used to run all "calc_metric_*" methods.
Something that looks a bit like:
class CalculateMetrics:
...
def calc_metric_x1(self):
...
def calc_metric_x2(self):
...
def calc_metric_x3(self):
...
def calc_metric_x4(self):
...
...
def calc_metric_x50(self):
...
def run_all(self):
method_list = [m for m in dir(self)
if callable(getattr(self, m))
and m.startswith('calc_metric_')]
for m in method_list:
# Call each method
getattr(self, m)()
The use of getattr
referencing the method's name doesn't seem optimal to me. Is there a better way to achieve this in Python?
CodePudding user response:
You could use a decorator function that collects them like this:
def calc_metric(func):
if func not in calc_metric.calc_metric_funcs:
calc_metric.calc_metric_funcs.append(func)
return func
calc_metric.calc_metric_funcs = []
Then you need to decorate all the desired functions with @calc_metric
:
@calc_metric
def calc_metric_x1(self):
...
@calc_metric
def calc_metric_x2(self):
...
...
@calc_metric
def calc_metric_x50(self):
...
And you run_all()
function will be like this:
def run_all(self):
for f in calc_metric.calc_metric_funcs:
f(self)
Note that the calc_metric
function must be declared outside of the CalculateMetrics
class.