I have a list of objects of a class. When I change the object that I use in the append function, the list also changes. Why is that? I am coming from C++ so this is quite strange.
I have the following code:
class state:
def __init__(self):
self.x=list([])
self.possibleChests=list([])
self.visitedChests=list([])
def __str__(self):
print "x ",
print self.x
print "possibleChests ",
print self.possibleChests
print "visitedChests ",
print self.visitedChests
return ""
def addKey(self,key):
self.x.append(key)
def __eq__(self,other):
if isinstance(other,self.__class__):
return self.__dict__==other.__dict__
else:
return False
current_state=state()
current_state.addKey(4)
current_state.possibleChests.extend([1,2,4])
current_state.visitedChests.append(5)
visitedStates=list([])
visitedStates.append(current_state)
current_state.addKey(5)
if(current_state in visitedStates):
print "Got ya!!"
else:
print "Not in list!!"
And I get the output:
Got ya!!
I have changed the current_state object so it should not be in the list.
Your state
object is mutable. When you call current_state.addKey(5)
you modify current_state
but all pointers to it still point to it. And in python list only contain pointers to objects. You have same thing with lists which are mutable :
l1 = [ 1, 2]
l2 = l1
l1.append(3)
l2
=> shows [1, 2, 3]
You cannot have same thing with strings (for example) because they are immutable. You cannot modify them, but only point to another string
s1 = "abc"
s2 = s1
s1 = "def"
s2
=> shows "abc"
This is a common source of mistake when you create an object outside of a loop and in the loop modify it and add it to a list : at the end of the loop you have a list containing n times the same object with last value. And this is not specific to python but can be observed in Java and even in C or C++ if you only store pointers to a mutable object.
C++ example (it is not good C++ but the minimum to exhibits the problem)
class pair {
public:
int key;
int val;
}
pair* map[5];
pair p;
for (i=0; i<5; i++) {
p.key = i;
p.val = 2 * i;
map[i] = &p; // only store pointer
}
At the end of the loop map
contains 5 pointers to the same pair
with key=4
and val=8
When I change the object that I use in the append function, the list also changes.
Add a copy of the object or a new object rather than sharing the same object.
Operations like =
and append
share a reference and do not create new objects. You can create a new distinct state by calling state() again. You can create a copy by using the copy module:
from copy import deepcopy
visitedStates.append(deepcopy(current_state))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With