Iteratively create subclass and store objects as class attribute

Viewed 114

I have a class that does some complex calculation and generates some result MyClass.myresults.

MyClass.myresults is actually a class itself with different attributes (e.g. MyClass.myresults.mydf1, MyClass.myresults.mydf2.

Now, I need to run MyClass iteratively following a list of scenarios(scenarios=[1,2,[2,4], 5].

This happens with a simple loop:

    for iter in scenarios:
        iter = [iter] if isinstance(iter, int) else iter
        myclass = MyClass() #Initialize MyClass
        myclass.DoStuff(someInput) #Do stuff and get results
        results.StoreScenario(myclass.myresults, iter)

and at the end of each iteration store MyClass.myresults.

I would like to create a separate class (Results) that at each iteration creates a subclass scenario_1, scenario_2, scenario_2_4 and stores within it MyClass.myresults.

class Results:
    # no initialization, is an empty container to which I would like to add attributes iteratively
    class StoreScenario:
        def __init__(self, myresults, iter):
            self.'scenario_'.join(str(iter)) = myresults #just a guess, I am assuming this is wrong

Suggestions on different approaches are more than welcome, I am quite new to classes and I am not sure if this is an acceptable approach or if I am doing something awful (clunky, memory inefficient, or else).

2 Answers

There's two problems of using this approach, The first one is, Result class (separate class) only stores modified values of your class MyClass, I mean, they should be the same class.

The second problem is memory efficiency, you create the same object twice for storing actual values and modified values at each iteration.

The suggested approach is using a hashmap or a dictionary in python. Using dictionary you are able to store copies of modified object very efficient and there's no need to create another class.

class MyClass:
  def __init__(self):
    # some attributes ...
    self.scenarios_result = {}

superObject = MyClass()

for iter in scenarios:

    iter = [iter] if isinstance(iter, int) else iter

    myclass = MyClass() #Initialize MyClass
    myclass.DoStuff(someInput) #Do stuff and get results

    # results.StoreScenario(myclass.myresults, iter)

    superObject.scenarios_result[iter] = myclass

So I solved it using setattr:

class Results:

    def __init__(self):
        self.scenario_results= type('ScenarioResults', (), {}) # create an empty object


    def store_scenario(self, data, scenarios):
        scenario_key = 'scenario_' + '_'.join(str(x) for x in scenarios)
        setattr(self.simulation_results, scenario_key, 
                subclass_store_scenario(data))

class subclass_store_scenario:
    def __init__(self, data):

        self.some_stuff = data.result1.__dict__
        self.other_stuff = data.result2.__dict__

This allows me to call things like:

results.scenario_results.scenario_1.some_stuff.something
results.scenario_results.scenario_1.some_stuff.something_else

This is necessary for me as I need to compute other measures, summary or scenario-specific, which I can then iteratively assign using again setattr:

    def construct_measures(self, some_data, configuration):
        for scenario in self.scenario_results: 
            #scenario is a reference to the self.scenario_results class. 
            #we can simply add attributes to it
            setattr(scenario , 'some_measure',
                    self.computeSomething(
                            some_data.input1, some_data.input2))

Related