これを抽象的に説明するのは難しいので、(簡略化して抜粋した)例を挙げましょう。
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)
しかし、これはさらにハックな気がします。
各メソッドを共通のスーパークラスのインスタンスにすることもできますが、これはやり過ぎのように感じます。