我们可以让父类初始化的频率低于子类吗?

-1 投票
3 回答
71 浏览
提问于 2025-04-13 19:10

我尝试用类的继承来绘制不同频率(f)和幅度(a)的正弦波。但是我觉得这个方法运行得不够高效。

这是我的代码,我把共同的属性fa放在父类里,而把变量t放在子类里。

import math
from matplotlib import  pyplot   as plt

class Parent:
    def __init__(self, f, a):
        self.freq = f
        self.ampl = a
        self.color = (f/a/3, (f/a)/2, (f/a)) # some random RGB numbers

class Child(Parent):
    def __init__(self, t, f, a):
        super(Child, self).__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 (f,a) in [(0.05,1.5), (0.1,1)]: 
        color = Parent(f, a).color
        time = [i for i in range(50)]
        cl = [Child(x, f, a).volt() for x in time]
        plt.plot(time, cl, color=color)
    plt.xlabel("time")
    plt.ylabel("amplitude")
    plt.title(f"Voltage waveform for different frequencies")
    plt.show()

这个方法是可以工作的。但每次创建一个Child(x, f, a)的实例时,它都会运行super().__init__,而这个部分对于每个变量x来说都是不变的。我在想有没有办法让Parent在外层循环中运行,针对变量fa,而让Child在内层循环中运行,针对变量x

3 个回答

0

其实,使用类变量的话,我们可以省去类继承的部分:

import math
from matplotlib import  pyplot   as plt

class Parent:
    freq = None
    ampl = None
    color = None
    def __init__(self, f, a):
        Parent.freq = f
        Parent.ampl = a
        Parent.color = (f/a/3, (f/a)/2, (f/a))

class Child:
    def __init__(self, t):
        self.time = t
    def volt(self):
        omega = 2*math.pi*Parent.freq
        return Parent.ampl * math.sin(omega*self.time)

if  __name__ == '__main__':
    for (f,a) in [(0.05,1.5), (0.1,1)]: 
        Parent(f, a) 
        time = [i for i in range(50)]
        cl = [Child(x).volt() for x in time]    
        plt.plot(time, cl, color=Parent.color) 

    plt.xlabel("time")
    plt.ylabel("amplitude")
    plt.title(f"Voltage waveform for different frequencies")
    plt.show()
1

我觉得这里用到 ParentChild 这样的类没有什么好理由。这些类里的大部分属性都是设置了但没有被读取,而且没有哪个属性需要被读取超过一次。你可以再考虑一下,真的有必要用这些类吗?

我建议的代码是 --

import math
from matplotlib import pyplot as plt

def make_color(freq, ampl):
    return (freq / ampl / 3, freq / ampl / 2, freq / ampl)  # some random RGB numbers

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 = [i for i in range(50)]
        cl = [calc_volt(x, freq, ampl) for x in time]
        plt.plot(time, cl, color=color)

    plt.xlabel("time")
    plt.ylabel("amplitude")
    plt.title("Voltage waveform for different frequencies")
    plt.show()

我同意,对于这样简单的问题,确实不需要用类。不过我用这个例子是为了探索不同的设计方式。

没问题。那我们继续用类。

Parent.__init__ 里,最耗时的部分是计算 color,而且在 Child 的实例中从来没有用到这个 color,所以这个计算是浪费的。我建议可以用 functools.cached_property 来让它变得懒加载。

相关的部分可以改成 ---

from functools import cached_property

class Parent:
    def __init__(self, f, a):
        self.freq = f
        self.ampl = a

    @cached_property
    def color(self):
        return (f / a / 3, (f / a) / 2, (f / a))  # some random RGB numbers
-1

你可以在父类中使用静态变量或类变量。

import math
from matplotlib import pyplot as plt

class Parent:
    freq = None
    ampl = None

    def __init__(self):
        self.color = (self.freq/self.ampl/3, (self.freq/self.ampl)/2, (self.freq/self.ampl)) # some random RGB numbers

class Child(Parent):
    def __init__(self, t):
        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.freq = freq
        Parent.ampl = ampl
        color = Parent().color
        time = [i for i in range(50)]
        cl = [Child(x).volt() for x in time]
        plt.plot(time, cl, color=color)

    plt.xlabel("time")
    plt.ylabel("amplitude")
    plt.title("Voltage waveform for different frequencies")
    plt.show()

撰写回答