Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: List of Objects changes when the object that was input in the append() function changes

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.

like image 323
user2105632 Avatar asked Oct 21 '25 13:10

user2105632


2 Answers

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

like image 117
Serge Ballesta Avatar answered Oct 23 '25 02:10

Serge Ballesta


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))
like image 36
Raymond Hettinger Avatar answered Oct 23 '25 03:10

Raymond Hettinger



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!