
本文探讨在面向对象设计中,当父类初始化包含昂贵或不变的计算(如颜色生成)时,如何通过函数式重构或延迟计算(cached_property)避免子类频繁重复执行相同逻辑。
本文探讨在面向对象设计中,当父类初始化包含昂贵或不变的计算(如颜色生成)时,如何通过函数式重构或延迟计算(`cached_property`)避免子类频繁重复执行相同逻辑。
在您的正弦波绘图示例中,Parent 类的 __init__ 方法不仅保存了频率 freq 和振幅 ampl,还立即计算了依赖于二者的 color 属性。而每次创建 Child 实例(对应一个时间点 t)时,都会重新调用 super().__init__(f, a),导致完全相同的 color 被重复计算数十次——这既低效,也违背单一职责原则。
推荐方案一:优先考虑函数式设计(更简洁、高效)
对于此类参数固定、行为纯函数化的场景,类并非必需。将逻辑拆解为独立函数,明确输入输出,代码更易测试、复用和理解:
import math
from matplotlib import pyplot as plt
def make_color(freq, ampl):
return (freq / ampl / 3, freq / ampl / 2, freq / ampl)
def calc_volt(time, freq, ampl):
omega = 2 * math.pi * freq
return ampl * math.sin(omega * time)
if __name__ == "__main__":
for freq, ampl in [(0.05, 1.5), (0.1, 1)]:
color = make_color(freq, ampl)
time_points = list(range(50))
voltages = [calc_volt(t, freq, ampl) for t in time_points]
plt.plot(time_points, voltages, color=color)
plt.xlabel("time")
plt.ylabel("amplitude")
plt.title("Voltage waveform for different frequencies")
plt.show()推荐方案二:保留类结构,但优化初始化逻辑
若需维持类设计(例如为未来扩展预留接口、集成其他 OOP 特性),应分离「不变配置」与「可变状态」:
- 将 freq/ampl 作为核心配置保留在父类;
- 使用 @functools.cached_property 延迟且仅计算一次 color,避免构造时冗余运算;
- 子类 Child 仅管理与时间相关的动态数据(如 time),不重复触发父类开销。
from functools import cached_property
import math
from matplotlib import pyplot as plt
class Parent:
def __init__(self, f, a):
self.freq = f
self.ampl = a
@cached_property
def color(self):
# 仅首次访问时计算,后续直接返回缓存值
return (self.freq / self.ampl / 3,
self.freq / self.ampl / 2,
self.freq / self.ampl)
class Child(Parent):
def __init__(self, t, f, a):
# 父类初始化不再计算 color,仅存配置
super().__init__(f, a)
self.time = t # 动态状态
def volt(self):
omega = 2 * math.pi * self.freq
return self.ampl * math.sin(omega * self.time)
if __name__ == "__main__":
for freq, ampl in [(0.05, 1.5), (0.1, 1)]:
# 复用同一 Parent 配置实例(color 计算仅一次)
config = Parent(freq, ampl)
time_points = list(range(50))
# Child 实例化仍需每个 t 点,但父类初始化已轻量
voltages = [Child(t, freq, ampl).volt() for t in time_points]
plt.plot(time_points, voltages, color=config.color)
plt.xlabel("time")
plt.ylabel("amplitude")
plt.title("Voltage waveform for different frequencies")
plt.show()关键总结:
- ✅ 性能优先:对无状态、纯计算逻辑,函数式优于类;避免为“看起来像 OOP”而滥用继承。
- ✅ 缓存即优化:@cached_property 是解决「父类昂贵属性在子类中被多次重复计算」的经典方案,线程安全且自动管理生命周期。
- ⚠️ 警惕反模式:若子类实例高频创建且父类 __init__ 包含非必要计算,说明职责划分失当——应将配置类(Configuration)与运行时实体(Instance)分离。

















