如何避免重新定义仅在输入和输出数据类型转换方面与另一个 class 不同的 class?

How to avoid re-defining a class that differs just for inputs and outputs data type conversions from another class?

我有一个 class,有两种方法:'fit' 和 'transform'。这些方法应该与特定数据类型(多索引 pandas DataFrame)一起使用,但我想将它与另一种数据类型(numpy 3d 数组)一起使用,但复制和粘贴对我来说似乎不方便class 只需在输入和输出中添加数据转换。

这里的 DRY 最佳实践是什么?在方法上使用装饰器?

下面是我的意思的简单伪代码

import numpy as np
import pandas as pd


class Transformer2d:

  def __init__(self):
    pass

  def fit(self, X, y):
    self.foo = np.mean(X['0'])
    return self

  def transform(self, X):
    X['0'] = X['0'] / self.foo
    return X


class Transformer3d:
  """
  I would not like to create this class because is very similar 
  to the previous one except for data type conversion for inputs and outputs
  """

  def __init__(self):
    pass

  def fit(self, X, y):
    X_ = threedim2twodim(X)  # difference with the previous class
    self.foo = np.mean(X_['0'])
    return self

  def transform(self, X):
    X_ = threedim2twodim(X)  # difference with the previous class
    X_['0'] = X_['0'] / self.foo
    return twodim2threedim(X_, X.shape[0])  # difference with the previous class


# data type conversion functions
def threedim2twodim(X:np.ndarray):
    return X.swapaxes(2, 1).reshape(-1, X.shape[1])


def twodim2threedim(X:np.ndarray, n_samples:int=-1):
    return X.reshape(n_samples, -1, X.shape[1]).swapaxes(1, 2)

在您的方法中,您可以检查输入的 type() 并决定您希望对剩余的 body 做什么。

您可以为此使用 functools.singledispatchmethod。一个简单的演示是重载 class 的 __init__() 函数以获取整数或浮点数,并使 class 根据输入类型具有不同的行为。

from functools import singledispatchmethod

class Point:
    @singledispatchmethod
    def __init__(self, x: int, y: int):
        self.x = x
        self.y = y

    @__init__.register
    def _(self, x: float, y:float):
        self.x = int(x)
        self.y = int(y)

    def norm(self):
        return self.x**2 + self.y**2

    
integer_p = Point(3,4)
print(f"Int norm: {integer_p.norm()}")

float_p = Point(3.1, 4.2)
print(f"Float norm: {float_p.norm()}")

这样您就不必使用 isinstance 进行任何类型检查。