4

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.

9
  • 1
    You don't put a copy into the list - it's a reference to the exact same object. Commented Jun 21, 2014 at 20:52
  • Is it different from the prompt? Because on the prompt, when I change the variable, the list doesn't change. How can I add by value in the list? Commented Jun 21, 2014 at 20:54
  • It's the same in the prompt; without seeing the exact code I can't explain why you think it's different. You can't "add by value" - it's all references in Python. Names like current_state and collections like list just provide references to the underlying objects. If you want a separate version of the object, define a method to copy it - see docs.python.org/2/library/copy.html Commented Jun 21, 2014 at 20:57
  • You might find this useful: python.net/~goodger/projects/pycon/2007/idiomatic/… Commented Jun 21, 2014 at 20:59
  • On the prompt I did the following:>>> b=[] >>> a=5 >>> b.append(a) >>> a=6 >>> b [5] Commented Jun 21, 2014 at 21:01

2 Answers 2

3

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

Sign up to request clarification or add additional context in comments.

1 Comment

This does not answer OP's question.
1

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))

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.