Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python : How to create a dynamic list of class values

I have tried to find the anwser to that question, but I cannot find the good Keywords ...

I want to know how can I create a list of value help in instances of a class. What I do not want is that :

class Test:
    def __init__(self,i)
        self.i = i

inst1 = Test(2)
inst2 = Test(5)

MyList = [inst1.i,inst2.i]

At that point MyList = [2,5] if I change the value if inst1

inst1.i = 4
print MyList 
[2,5]

MyList is STILL [2,5] but I want it to be updated to [4,5]

print MyList
[4,5]

So my question is that, how do I create a list that points to the variable and not the variable value ?

If you want to know why : I am running a MonteCarlo simulation in which I have a lot of proteins, each with one energy value, and each Protein is instantiated from a Protein class.

class Protein:
    def __init__(self,sequence,energy):
        self.sequence = sequence
        self.energy = energy

That energy value of some proteins gets updated during a montecarlo simulation. I need a list of all the energies to perform some calculation on the distribution. Right know, I updated the list with a for loop, but it would be way more efficient if I could have a list that points to the variable, that way every time an energy in the Protein class is changed the list is updated automatically.

Thanks a lot !

like image 807
Xqua Avatar asked Dec 11 '13 22:12

Xqua


1 Answers

A very good question.

Two bullet-points on the way to your answer:

  1. classical variable vs. python label-like "variables"/identifiers
  2. mutable vs immutable python-types

You have to keep in mind, that in python the name variable may be misleading if you come from another programing language. It may be better not to talk about variables, but about "labels".

When you create an object like: myvar = 1 you create (oversimplification) an object 1 and to keep track of it you attached a label myvar to it. So if you want to talk about the object 1 you could say: "The object labeled with myvar." You may reattach the label to another object by relabeling: myvar = 2. If myvar was the only label on 1 you just lost the object 1 and it will be garbage collected.

In your case:

inst1 = Test(2)  # create 2 and attach it to inst1.i
inst2 = Test(5)  # create 5 and attach it to inst2.i
MyList = [inst1.i,inst2.i]  # list of objects: [2 ,5]

So you now have a list of 2 immutable objects! Your next step:

inst1.i = 4

creates a new object 4 and reattaches the inst1.i label onto it! You just lost your handle on object 2. But because it's in the MyList collection it's still referenced and won't be garbage collected.

Now on to bullet point 2:

A nice overview of mutable and immutable objects, shows that basically all primitive types are immutable and most collections are mutable. The difference is. that mutable objects can get an in-place edit, while immutable objects need to be replaced.

Or to keep the label anology: On immutable objects you need to move the "Label" while on mutable you hold the "Label" in place and move the object under it.

Now back to your problem:

Basically you need to change perspective! MyList is NOT an Array, but a collection. So in order not to reinvent your venue of solution i would recommend to keep the Test objects in your list, rather than their values!:

MyList = [inst1,inst2]

If you change now inst1.i = 4, the following happens:

  1. you create the object 4
  2. you attach the attribute inst1.i to it ("re-label" it)
  3. Your object becomes a mediator between the list and your new object
  4. You can access 4 over MyList[0].i or inst1.i

Mission accomplished! ;-)

for value in MyList:
    print value.i

inst1.i = 4    
raw_values = [o.i for o in MyList]
[4, 5]

inst1.i = 2
raw_values = [o.i for o in MyList]
[2, 5]
like image 99
Don Question Avatar answered Nov 08 '22 16:11

Don Question