简体   繁体   中英

Why does this happen with classes

I have written following class which does the following:

class abc:
    def __init__(self):
        self.Values = []
    def add_code(self):
        lastval = self.Values
        print "self.Values  , ", self.Values
        print "lastval  , ", lastval
        lastval.append(1)
        print "self.Values 1, ", self.Values
        print "lastval 1 , ", lastval

        lastval.append(2)
        print "lastval 2 , ", lastval
        print "self.Values 2 , ", self.Values
        lastval.append(3)
        print "lastval 3 , ", lastval
        print "self.Values 3 , ", self.Values
        lastval.append(4)
        print "last val 4 ", lastval
        print "self.Values 4 , ", self.Values
        lastval = []
        print "last value is emtpy now? , ", lastval
        print "But the self.Values is not", self.Values
        return lastval

When I run this code I see that the variable lastval gets appended with the values and so does the self.Values But when I initialize the lastval with empty list, I still see self.Values holds to the values. What could be the reason

Why would you think otherwise? At first, you assign lastval to point to the same list as self.Values , so mutations to one will be seen in the other. But when you do lastval = [] you simply rebind lastval to a new list, you don't affect self.Values at all.

After the __init__ method has run, we have two objects in memory:

#1 Instance of abc
#2 Array

They contain:

#1 Instance of abc
    Values : Reference to #2

#2 Array
    [ ]

Now we call add_code and it runs:

lastval = self.Values
print "self.Values  , ", self.Values
print "lastval  , ", lastval

At this point, both lastval and self.Values are references to object #2, the array. So we have:

#1 Instance of abc
    Values : Reference to #2

#2 Array
    [ ]

Local variables
    self : Reference to #1
    lastval : Reference to #2

Continuing...

lastval.append(1)
print "self.Values 1, ", self.Values
print "lastval 1 , ", lastval

The append method modifies object #2. So now we have:

#1 Instance of abc
    Values : Reference to #2

#2 Array
    [ 1 ]

Local variables
    self : Reference to #1
    lastval : Reference to #2

This continues similarly...

lastval.append(2)
print "lastval 2 , ", lastval
print "self.Values 2 , ", self.Values
lastval.append(3)
print "lastval 3 , ", lastval
print "self.Values 3 , ", self.Values
lastval.append(4)
print "last val 4 ", lastval
print "self.Values 4 , ", self.Values

So now we have:

#1 Instance of abc
    Values : Reference to #2

#2 Array
    [ 1, 2, 3, 4 ]

Local variables
    self : Reference to #1
    lastval : Reference to #2

At this point, we do something different:

lastval = []

This is an assignment to a local variable. It doesn't do anything to object #2. It creates a new array. So finally we have:

#1 Instance of abc
    Values : Reference to #2

#2 Array
    [ 1, 2, 3, 4 ]

#3 Array
    [ ]

Local variables
    self : Reference to #1
    lastval : Reference to #3

As you can see, lastval and self.Values now refer to different objects.

The important thing to understand is the difference updating a variable to reference different objects, and mutating an existing object. For an in-depth discussion, see http://docs.python.org/3/reference/datamodel.html (That document is for Python 3, but there is no major difference in these concepts between Python 2 and Python 3.)

Classes have nothing (or not much) to do with this. The underlying effect is that several variables can hold the same list (this happens via assignment). And if you then change the list, all variables seem to change.

You might want to create copies of the lists to avoid that.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM