很难用抽象来描述这一点,所以让我举一个(简化和剪断的)例子:
class ClassificationResults(object):
#####################################################################################################################
# These methods all represent aggregate metrics. They all follow the same interface: they return a tuple
# consisting of the numerator and denominator of a fraction, and a format string that describes the result in terms
# of that numerator, denominator, and the fraction itself.
#####################################################################################################################
metrics = ['recall', 'precision', 'fmeasure', 'f2measure', 'accuracy']
# ...
def recall(self):
tpos, pos = 0, 0
for prediction in self.predictions:
if prediction.predicted_label == 1:
pos += 1
if prediction.true_label == 1:
tpos += 1
return tpos, pos, "{1} instances labelled positive. {0} of them correct (recall={2:.2})"
def precision(self):
tpos, true = 0, 0
for prediction in self.predictions:
if prediction.true_label == 1:
true += 1
if prediction.predicted_label == 1:
tpos += 1
return tpos, true, "{1} positive instances. We labelled {0} correctly (precision={2:.2})"
# ...
def printResults(self):
for methodname in self.metrics:
(num, denom, msg) = getattr(self, methodname)()
dec = num/float(denom)
print msg.format(num, denom, dec)
有没有更好的方法来表明这些方法都属于同一个“家族”,并允许在循环中调用它们而不每次都命名它们?
我过去做过的另一种方法是使用公共前缀命名方法,例如
def metric_precision(self):
tpos, true = 0, 0
for prediction in self.predictions:
if prediction.true_label == 1:
true += 1
if prediction.predicted_label == 1:
tpos += 1
return tpos, true, "{1} positive instances. We labelled {0} correctly (precision={2:.2})"
# ...
def printResults(self):
for methodname in dir(self):
meth = getattr(self, methodname)
if methodname.startswith('metric_') and callable(meth):
(num, denom, msg) = getattr(self, methodname)()
dec = num/float(denom)
print msg.format(num, denom, dec)
但这感觉更加骇人听闻。
我也可以将每个方法变成一个公共超类的实例,但这感觉有点过头了。