如何避免重新定义仅在输入和输出数据类型转换方面与另一个 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
进行任何类型检查。
我有一个 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
进行任何类型检查。