一种模式,其中一个类具有许多相似的方法(相同的类型签名,相似的语义)

很难抽象地描述这一点,所以让我举一个(简化和摘录的)示例:


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})"


我还可以将每个方法都转换为一个公共超类的实例,但是这感觉有点过头了。


拉风的咖菲猫
浏览 155回答 3
3回答

慕勒3428872

您可以使用类装饰器来生成度量标准方法的列表。这样做的好处是,您可以在类定义时生成度量标准方法的列表,而不是每次 printResults调用时都重新生成该列表。另一个优点是您不必手动维护ClassificationResults.metrics列表。您无需在两个位置上拼写方法的名称,因此它是DRY-er,而且,如果您添加了另一个指标,则不必记住也要更新ClassificationResults.metrics。您只需要给它一个以开头的名称即可metrics_。由于每种度量方法都返回一个相似的对象,因此您可以考虑将该概念形式化为类(例如Metric,下面的)。这样做的一个好处是您可以定义一种__repr__方法来处理结果的打印方式。注意printResults (下面)变得多么简单。def register_metrics(cls):    for methodname in dir(cls):        if methodname.startswith('metric_'):            method = getattr(cls, methodname)            cls.metrics.append(method)    return clsclass Metric(object):    def __init__(self, pos, total):        self.pos = pos        self.total = total    def __repr__(self):        msg = "{p} instances labelled positive. {t} of them correct (recall={d:.2g})"        dec = self.pos / float(self.total)        return msg.format(p=self.total, t=self.pos, d=dec)@register_metricsclass ClassificationResults(object):    metrics = []    def metric_recall(self):        tpos, pos = 1, 2        return Metric(tpos, pos)    def metric_precision(self):        tpos, true = 3, 4        return Metric(tpos, true)    def printResults(self):        for method in self.metrics:            print(method(self))foo = ClassificationResults()foo.printResults()
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python