3

I have a class called run_c which is being used to initialize and execute the run of a kinematics simulation. I assign default values to the attributes of run_c, such as x, before run_c.__init__() is executed. All __init__() is doing is extracting user-input values, aggregated into a dictionary, and assigning them to corresponding attributes in run_c if they exists. For example...

import vars.Defaults as dft
class run_c:

   ...
   dt     = dft.dt
   x      = dft.x0
   states = [ [], [], [], [] ]
   ...

   def __init__(self, input):
      for key in input.keys():
         if hasattr(self, key): setattr(self, key, input[key])
      ...
      self.execute()

run_c.states is a list of lists that is being used to record the values of run_c attributes as they change with timesteps. Later, within run_c.execute(), I am storing x values in states[1], incrementing the timestep dt, and updating x using velocity and timestep. It's pretty simple stuff, right?...

Here's where the problem begins, though. The first time that the instance of run_c is created, initialized, and executed, it runs perfectly. However, I am operating this simulation by creating, initializing, and executing multiple runs based off of list read from a JSON file. As such, in the driver module...

from Run import run_c
def main():
   ...
   for runEntry in runList:
      currRun = run_c(runEntry)
      ...
   ...

What happens is that all the values that were stored in run_c.states do not get wiped after each iteration of the loop. I thought that new instances of run_c are being created every time I run the loop so as to execute __init__() fresh with new information. Why are the data values, such as old values for x, being retained after the end of each loop?

Update: When I add in a line of code to reset the values of states back to empty lists within __init__(), the problem goes away. But this shouldn't be a necessary step in what I want to do...should it?

martineau
  • 119,623
  • 25
  • 170
  • 301
S. Gamgee
  • 501
  • 5
  • 16
  • How often are you creating a *new, empty* list for `states`? Once: while defining the class. The list object is not getting reset for each new instance. – deceze Aug 16 '16 at 14:23
  • So is the list `states` only being assigned and never used? When I mention `self.states`, is that a completely separate entity? Or is it more similar to global variables than to class variables? – S. Gamgee Aug 16 '16 at 14:26

2 Answers2

8

dt, x, and states are defined as class variables, not instance variables. Every instance of that class that you make will share them. If you need them to be initialized each time you generate a new instance, that's exactly what __init__() is for:

class run_c:

   def __init__(self, input):
      ...
      self.dt     = dft.dt
      self.x      = dft.x0
      self.states = [ [], [], [], [] ]
      ...

      for key in input.keys():
         if hasattr(self, key): setattr(self, key, input[key])
      ...
      self.execute()
glibdud
  • 7,550
  • 4
  • 27
  • 37
0

In addition to the existing answer: you can initialize these variables in the __new__ method.

class A:
    val = 1

    def __new__(cls, v):
        t = super().__new__(cls)
        t.val = v
        return t

    def __init__(self, v):
        val = v

a, b = A(1), A(2)

print(a.val, b.val)

If you remove the __new__ method, the output'd be 1 1 and otherwise 1 2.

ForceBru
  • 43,482
  • 10
  • 63
  • 98
  • @BruceDavidWilner, no, nobody'd get mired in class hierarchies as `super` doesn't care about it. No, the semantics of these 'magic' methods is not obscure: you write them once, and when you use your classes, you don't see them at all. This answer shows how _not to_ move the variables' definitions into `__init__` and achieve the OP's goal, that's it. – ForceBru Aug 16 '16 at 16:02