如何实现返回继承类的类方法,优化自定义数据拟合类的属性传递
解决方法:优雅实现子类继承父类属性的拟合类
首先,咱们先搞定你最初遇到的TypeError:你定义的fit方法没有包含self参数!当你用实例调用f.fit(3)时,Python会自动把实例f作为第一个参数传递给方法,但你的方法定义只接受lookback这一个参数,所以就会报“takes 1 positional argument but 2 were given”的错误。这是Python类方法的基础问题,所有实例方法都需要把self作为第一个参数。
接下来回到你核心的需求:让fitter_fit自动继承fitter的所有属性,不用手动逐个传递。这里有两种简洁的实现方式:
方式一:利用继承+关键字参数展开
让fitter_fit继承fitter,然后在fit方法里用**vars(self)把当前fitter实例的所有属性打包成关键字参数传递给子类,子类通过父类构造方法初始化这些属性:
import datetime as dt import pandas as pd from scipy.optimize import curve_fit from dateutil import relativedelta import numpy as np def ex(x, a, b): """Exponential function""" return a * b**x def p2y(idx): """Evaluate number of periods to a year""" return int(12/(relativedelta.relativedelta(idx[-1],idx[-2]).months)) class fitter: """Creates fit parameters over a lookback number of years""" def __init__(self, use_y, kind, true_y=None): self.use_y = use_y # 简化true_y的赋值逻辑 self.true_y = true_y if true_y is not None else use_y self.kind = kind self.p = p2y(use_y.sort_index().index) def fit(self, lookback): # 用**vars(self)自动传递当前实例的所有属性 return fitter_fit(lookback, **vars(self)) class fitter_fit(fitter): """Perform fit over lookback number of years""" def __init__(self, lookback, **kwargs): # 先调用父类构造方法,初始化继承的属性 super().__init__(**kwargs) self.lookback = lookback # 执行拟合逻辑 n = int(lookback * self.p) x = np.linspace(1, n, n) dates = self.use_y.index[-n:] y = self.use_y.values[-n:] if self.kind == 'exp': self.popt, self.pcov = curve_fit(ex, x, y) # 测试代码 qtrly=pd.DataFrame( index=[dt.datetime(2020,1,1),dt.datetime(2020,4,1),dt.datetime(2020,7,1),dt.datetime(2020,10,1)], data={'fre':[0.55,0.6,0.62,0.7]} ) f=fitter(qtrly.fre,'exp') fit_result = f.fit(3) # 查看拟合参数 print(fit_result.popt) # 验证继承的属性 print(fit_result.true_y.equals(qtrly.fre))
方式二:直接复制父类实例的属性字典
如果你不想依赖继承的构造方法,也可以直接把父类实例的属性字典复制到子类实例中,这种方式更直接:
class fitter: """Creates fit parameters over a lookback number of years""" def __init__(self, use_y, kind, true_y=None): self.use_y = use_y self.true_y = true_y if true_y is not None else use_y self.kind = kind self.p = p2y(use_y.sort_index().index) def fit(self, lookback): # 传递当前实例给子类构造方法 return fitter_fit(self, lookback) class fitter_fit: """Perform fit over lookback number of years""" def __init__(self, parent_fitter, lookback): # 直接复制父类实例的所有属性 self.__dict__.update(parent_fitter.__dict__) self.lookback = lookback # 执行拟合逻辑 n = int(lookback * self.p) x = np.linspace(1, n, n) dates = self.use_y.index[-n:] y = self.use_y.values[-n:] if self.kind == 'exp': self.popt, self.pcov = curve_fit(ex, x, y)
为什么这两种方式更优雅?
- 不用手动列出所有需要传递的属性,当你给
fitter类新增属性时,子类会自动继承,不用修改fit方法或子类构造。 - 代码更简洁,可读性更高,减少了重复代码。
- 方式一保持了类的层次结构,符合面向对象的设计原则;方式二更灵活,适合不需要严格继承关系的场景。
内容的提问来源于stack exchange,提问作者OldKingCole
相关产品推荐
相关产品推荐

