如何在Python类中更好地隔离数据 - python

我一直在从事一个电子零件计算器的项目。这是我的第一个全面Python项目,并且在此过程中经历了许多迭代。

数据的组织方式不尽如人意,我认为这很难改善程序。

我有一个模块类,其中有两个部分。每个部分都有各自独立的属性,整个模块本身具有一些部分不关心的属性,以及部分需要的属性。该模块还必须根据零件内部进行的独立计算的结果进行一些计算。 Here is a photo of the idea I'm trying to explain.顺便说一句,有时有些模块只有一部分,但是我可以通过应用一些0的数组来抑制另一部分。我希望能够有一个模块,其中一个部分完全缺失,但这不是我当前的目标。

问题是我的班级有大约100行self.XXX =开始时没有任何内容可以初始化所有内容,并且IMO的一些功能是重复的。在单步执行代码时遍历数据也非常困难-例如,我必须找到self.current__partA和self.current__partB之类的变量。我认为最好是使用诸如self.partA.current之类的东西。如果这样做的话,我认为它将更具可读性。

问题是,我尝试了子类,但似乎无法实现这种想法,因为在初始化子类时,必须初始化一个新的超类,这意味着有两个超类(两个模块,共4个部分,当我需要1个模块/ 2个部分时),因此我不能真正从超类访问两个子类的信息,因为每个子类都有自己的超类实例。

我还研究了内部类,但是存在一个问题,我认为我无法真正从内部类访问外部类,这违背了使用此类的目的。可以在某种程度上起作用,但是根据我所看到的,这会使我的代码更长,可读性更差。

我最初遇到的解决方案是字典,例如我不完全讨厌的东西,但这导致了真正的垃圾代码,对错误的容忍度很小。原因是,当您将列表添加到字典时,您将无法使用自动引发错误的函数。我可以查字典,但感觉不自然。在我看来,将每个值都保留为类变量并使用函数,获取器和设置器通过计算来操纵它会更有意义。

我的主要目标是有效地组织数据和代码,以便使用更少的代码行,并且程序更易于修改,并且更容易逐步完成该过程。我并没有完全被类结构所吸引,这似乎是适应我想做的最好的方法。有没有一种方法可以实现我在这里要问的问题,或者有没有一种更通用的Python方式来组织我的代码,这将导致更有效的解决方案?

class Module:
def __init__(self, module_file):
    temp_ic, temp_value = self.get__corrected_value(module_file)
    temp_if, temp_vf = self.get__corrected_value(module_file)
    self.ic_value = interp1d(temp_ic, temp_value, fill_value='extrapolate')
    self.ic_esw_on = interp1d(self.get__corrected_esw(module_file), self.get__corrected_esw(module_file["ESWON - IC ESWON"]), fill_value='extrapolate')
    self.ic_esw_off = interp1d(self.get__corrected_esw(module_file["IC - IC ESWOFF"]), self.get__corrected_esw(module_file["ESWOFF - IC ESWOFF"]), fill_value='extrapolate')
    self.rg_on_esw_on = interp1d(module_file["RGON - ESWON RGON"], module_file["ESWON - ESWON RGON"], fill_value='extrapolate')
    self.rg_off_esw_off = interp1d(module_file["RGOFF - ESWOFF RGOFF"], module_file["ESWOFF - ESWOFF RGOFF"], fill_value='extrapolate')
    self.ic_err = interp1d(self.get__corrected_esw(module_file["IC - IC ERR"]), self.get__corrected_esw(module_file["ERR - IC ERR"]), fill_value='extrapolate')
    self.if_vf = interp1d(temp_if, temp_vf, fill_value='extrapolate')
    self.rg_on_err = interp1d(module_file["RGON - ERR RGON"], module_file["ERR - ERR RGON"], fill_value='extrapolate')
    self.nameplate_vcc = module_file['Nameplate VCC']
    if module_file['vcc_ratio'] > 0:
        self.vcc_ratio = module_file['vcc_ratio']
    else:
        self.vcc_ratio = 0
    self.name = self.get__module_name(module_file)
    self.current__PartA = []
    self.current__PartB = []
    self.some_thing_loss__PartA = []
    self.esw_on_loss = []
    self.esw_off_loss = []
    self.esw_loss__PartA = []
    self.energy__PartA = []
    self.value__PartA = []
    self.some_thing_loss__PartB = []
    self.err_loss = []
    self.energy__PartB = []
    self.value__PartB = []
    self.rg_scalar_esw_on = None
    self.rg_scalar_esw_off = None
    self.rg_scalar_err = None
    self.value_dc__PartA = module_file['PartA value DC']
    self.value_dc__PartB = module_file['PartB value DC']
    self.value_dc__module = module_file['Module value DC']
    self.trans_r_values__PartA = module_file["PartA R Values"]
    self.trans_t_values__PartA = module_file["PartA T Values"]
    self.trans_r_values__PartB = module_file["PartB R Values"]
    self.trans_t_values__PartB = module_file["PartB T Values"]
    self.some_thing_loss_total__PartA = None
    self.some_thing_loss_total__PartB = None
    self.esw_on_loss_total = None
    self.esw_off_loss_total = None
    self.esw_loss_total = None
    self.err_loss_total = None
    self.device_loss_total__PartA = None
    self.device_loss_total__PartB = None
    self.module_loss_total = None
    self.delta_tcase_ave = None
    self.delta_value_ave__PartA = None
    self.delta_value_ave__PartB = None
    self.nominal_value_ave__PartA = None
    self.nominal_value_ave__PartB = None
    self.delta_value_max__PartA = None
    self.delta_value_max__PartB = None
    self.nominal_value_max__PartA = None
    self.nominal_value_max__PartB = None
    self.value_max_PartA_list = []
    self.value_max_PartB_list = []
    self.thermal_interp_is_four_degree = self.check__thermal_interp()
    self.switches_per_degree = None
    self.input_output_freq = None
    self.time_division = None
    self.input_t_sink = None
    self.step_size = None
    self.step_range = None
    self.sec_per_cycle_degree = None
    self.duty_p = None
    self.value_PartA_list = None
    self.value_PartB_list = None
    self.time_list = None
    self.rad_list = None
    self.value_max__PartA_thermo = None
    self.value_max__PartB_thermo = None
    self.value_max__time_value = None

def check__some_input_conditions_and_change_input(self):  # todo could this be cleaned?
    blah

def get__max_current(self):
    return max(self.nominal_value_max__PartB, self.nominal_value_max__PartA)

def set__some_module_values(self, is_three_level, system):  # todo call this something different, and break it out for 3-level
    blah

def set_values_for_both_parts(self, input_instance, system_instance, module_location=None):
    lots of blah

def set__current_PartA(self, current):
    self.current__PartA = current

def set__current_partB(self, current):
    blah

def calculate__another_other_loss_for_part_A(self, duty):
    blah

def calculate__another_loss_for_partB(self, duty):
    blah

def calculate__another_loss_for_partA(self, duty=None):
    blah

def calculate__some_loss_for_partA(self, duty=None):
    blah

def calculate__some_loss_for_partB(self, duty=None):
    blah

def calculate__energy_power_for_both_parts(self):
    blah

def calculate__temperatures_for_both_parts(self):
    blah

def calculate__max_temp(self):  # maybe split into PartA and PartB separately?
    self.create_thermal_resistance_dict()
    value_PartA_list = []
    value_PartB_list = []

    next_array_PartA = self.value__PartA
    next_array_PartA = self.rotate(next_array_PartA, -1)
    delta_p_PartA = [next_el - last_el for next_el, last_el in zip(next_array_PartA, self.value__PartA)]
    last_power_PartA = self.value__PartA[-1] - self.device_loss_total__PartA
    first_power_PartA = self.value__PartA[0] - self.device_loss_total__PartA
    value_dict_PartA_added = [self.get_PartA_value_from_time(i * self.sec_per_cycle_degree + self.value_max__time_value) for i in range(self.step_range)]
    value_dict_PartA_added = [old + new for old, new in zip(self.value_max__PartA_thermo, value_dict_PartA_added)]
    value_PartA_inst_init = [self.input_t_sink + self.delta_value_ave__PartA + self.delta_tcase_ave - last_power_PartA * self.value_max__PartA_thermo[i] + first_power_PartA * value_dict_PartA_added[i] for i in range(self.step_range)]

    delta_value_PartB = self.device_loss_total__PartB * self.value_dc__PartB
    next_array_PartB = self.value__PartB
    next_array_PartB = self.rotate(next_array_PartB, -1)
    delta_p_PartB = [next_el - last_el for next_el, last_el in zip(next_array_PartB, self.value__PartB)]
    last_power_PartB = self.value__PartB[-1] - self.device_loss_total__PartB
    first_power_PartB = self.value__PartB[0] - self.device_loss_total__PartB
    value_dict_PartB_added = [self.get_PartB_value_from_time(i * self.sec_per_cycle_degree + self.value_max__time_value) for i in range(self.step_range)]
    value_dict_PartB_added = [old + new for old, new in zip(self.value_max__PartB_thermo, value_dict_PartB_added)]
    value_PartB_inst_init = [self.input_t_sink + delta_value_PartB + self.delta_tcase_ave - last_power_PartB * self.value_max__PartB_thermo[i] + first_power_PartB * value_dict_PartB_added[i] for i in range(self.step_range)]

    for index in range(self.step_range):
        value_dict_PartA_fix = [value_dict_PartA_added[i] if i <= index else self.value_max__PartA_thermo[i] for i in range(self.step_range)]
        # value_dict_PartA_fix_orig = [val for val in value_dict_PartA_fix]
        value_dict_PartA_fix.reverse()

        new_value_PartA = self.rotate(value_dict_PartA_fix, index)
        new_value_PartA = new_value_PartA[:359]
        temp_add_vals_PartA = [delta_p * value for delta_p, value in zip(delta_p_PartA, new_value_PartA)]
        sum_temp_add_vals_PartA = sum(temp_add_vals_PartA)
        value_PartA_list.append(sum_temp_add_vals_PartA)

        value_dict_PartB_fix = [value_dict_PartB_added[i] if i <= index else self.value_max__PartB_thermo[i] for i in range(self.step_range)]
        # value_dict_PartB_fix_orig = [val for val in value_dict_PartB_fix]
        value_dict_PartB_fix.reverse()

        new_value_PartB = self.rotate(value_dict_PartB_fix, index)
        new_value_PartB = new_value_PartB[:359]
        temp_add_vals_PartB = [delta_p * value for delta_p, value in zip(delta_p_PartB, new_value_PartB)]
        sum_temp_add_vals_PartB = sum(temp_add_vals_PartB)
        value_PartB_list.append(sum_temp_add_vals_PartB)

    value_PartA_list = [value + diff for value, diff in zip(value_PartA_inst_init, value_PartA_list)]
    value_ave_PartA = self.nominal_value_ave__PartA - np.average(value_PartA_list)
    self.value_PartA_list = [value + value_ave_PartA for value in value_PartA_list]

    value_PartB_list = [value + diff for value, diff in zip(value_PartB_inst_init, value_PartB_list)]
    value_ave_PartB = self.nominal_value_ave__PartB - np.average(value_PartB_list)
    self.value_PartB_list = [value + value_ave_PartB for value in value_PartB_list]

    self.time_list = [i * self.sec_per_cycle_degree + self.value_max__time_value for i in range(self.step_range)]
    self.rad_list = [i * self.step_size for i in range(self.step_range)]

    self.nominal_value_max__PartA = max(value_PartA_list)
    self.nominal_value_max__PartB = max(value_PartB_list)
    self.delta_value_max__PartA = max(self.value_PartA_list) - self.input_t_sink
    self.delta_value_max__PartB = max(self.value_PartB_list) - self.input_t_sink
    self.value_max_PartA_list = value_PartA_list
    self.value_max_PartB_list = value_PartB_list

def rotate(self, l, n):
    return l[-n:] + l[:-n]

def do_calculation_for_either_part(self, step, spcd, index, scalar, growth, time):  # todo does everything need to be passed in?
    blah

def get_other_part's_value(self, time):  # todo could this be folded into below
    blah

def get_one_part's_value(self, time):
    blah

def integrate_value_for_other_part(self, step, spcd, start_time, index):  # todo could this be folded into below
    blah

def integrate_value_for_one_part(self, step, spcd, start_time, index):  # todo remove interp check
    blah

def create_some_dict_for_both_parts(self):  # todo could this be cleaned
    50 lines of blah

def get__other_corrected_array(self, array):  # todo could this be simplified?
    blah

def get__corrected_array(self, input arrays):  # todo is this necessary
    blah

def get__some_value(self, value):  # todo isn't there one of these already?
    blah

def get__module_name(self, module_file):
    blah

参考方案

评论员是正确的,因为MCVE肯定会改善您的帖子,因此我的回答有些局限。我只想指出,您的数据成员可以是任何python对象。

因此,如果您的数据访问模式将从将数据存储在熊猫中并作为熊猫与之交互而受益:

class YourClass:
    def __init__(self, data):
        self.data = # Your pandas df

或json:

import json
class YourClass:
    def __init__(self, data):
        self.data = json.loads(data)

还是numpy的:

class YourClass:
    def __init__(self, data):
        self.data = # Your numpy ndarray

然后您的班级可以简单地称为YourClass(data)

编辑:查看您的代码,在我看来,实际上所有self.value = None行都是多余的。如果它们是表格数据输入的成员,则可以将其初始化:

class Module:
    def __init__(self, data):
        self.data = pd.DataFrame()

一旦将它们初始化为空数据帧,它们的CRUD操作就可以映射到非常成熟的pandas CRUD操作。类似地,self.data = {}用于键值对数据结构,例如JSON,等等。对于其余的内容,您可以发现在通用的getter和setter中未定义data.key且不必费心初始化它们的情况。

Python __getitem__和in运算符导致奇怪的行为 - python

是什么解释了以下行为:class Foo: def __getitem__(self, item): print("?") return 1 f = Foo() 1 in f # prints one ? and returns True 5 in f # prints ? forever until you raise a Keyboa…

如何使用pass语句? - python

我正在学习Python,并且已经到达有关pass语句的部分。我正在使用的指南将其定义为通常用作占位符的Null语句。我仍然不完全明白那是什么意思。有人可以告诉我一个简单的/基本情况,在其中使用pass语句以及为什么需要它吗? 参考方案 假设您正在使用尚未实现的某些方法设计一个新类。class MyClass(object): def meth_a(self)…

python类中的变量范围 - python

在类中声明变量(在函数外部):所有类函数都可以访问它(基本上是公共变量)在类内的函数内声明变量:只有该函数才能访问它(在该函数范围内)在类内的函数内部声明带有self。(变量名)的变量:所有类函数都可以访问它(这与全局变量名有何不同?)并且由于没有私有/受保护的事物,所以所有事物都是公共的,因此可以从类外部访问所有从类内部访问的事物。我还有其他细微差别应该知…

如何在PyQt4的动态复选框列表中检查stateChanged - python

所以我要从PyQt4的列表中添加复选框。但是我找不到在Window类中对每个状态使用stateChanged的方法。这是从列表元素添加它们的功能: def addCheckbox(self): colunas = Graphic(self.caminho).getColunas() for col in colunas: c = QtGui.QCheckBo…

如何使用PySide重新实现事件并传递和传递参数 - python

我拼命地试图得到一个似乎很简单的问题的答案。因此,我的主要代码是具有QTextEdit的UI,并且我希望将字符数限制为140个。我认为,最好的方法是重新实现keyPressEvent和KeyReleaseEvent函数。为此,我要使用自定义的“文本编辑”小部件创建一个类:class CustomTextEdit(QtWidgets.QTextEdit): d…