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

时间:2018-12-05 14:52:08

标签: python class subclass inner-classes

我一直在从事一个电子零件计算器的项目。这是我的第一个全面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

1 个答案:

答案 0 :(得分:0)

评论员是正确的,因为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且不必费心初始化它们的情况。