Python language basics 28: modifying the referenced value
July 11, 2015 1 Comment
Introduction
In the previous post we discussed the basics of value and reference equality. We saw how to evaluate these equality types with the ‘==’ and ‘is’ operators. We also found an important difference between how value and reference types are handled in memory.
In this post we’ll look at another feature related to objects and equality, namely the effects of changing the referenced value.
Modifications through assignment
We’ve seen the assignment operator ‘=’ in action before:
x = 5
We can read this as ‘x becomes equal to 5’ or ‘x is assigned the value of 5’. This helps us distinguish in words between the ‘=’ and ‘==’ operators where ‘==’ tests for value equality as we saw in the previous post.
Let’s see what happens in the following bit of code:
x = 5 y = x x = 3 print(x) print(y)
Without knowing the printed values we could argue as follows about the expected outcome:
- The object called ‘x’ points to a value 5
- The object called ‘y’ will point to the same value as ‘x’ i.e. points to the previously created value 5
- We change the value of ‘x’ to 3
- As y and x point to the same value even y will be equal to 3
- Therefore both print statements will print 3
That’s in fact only partially true. The first two statements are true: x and y will point to the same value 5. However, x = 3 will NOT change the previously stored value 5 directly. Instead, a new integer value 3 will be created on the heap and x will instead point to that value. Its pointer has been redirected from 5 to 3. The object y still points to 5. The statement x = 3 does NOT change the stored value 5 directly. Therefore the print statements will print 3 and 5.
This feature is called object immutability in programming. The English word ‘immutable’ means something that cannot mutate, i.e. cannot change, cannot be changed. At first sight the above code seems to alter the value of x from 5 to 3 but that’s only appearance.
We see the same behaviour for strings:
s1 = 'hello' s2 = s1 s1 = 'bye' print(s1) print(s2)
This prints…
bye
hello
The ‘=’ assignment operator therefore only assigns a new value to an object. We can see that in the following example as well with a list:
myFirstList = ["small", "medium", "large", "x-large"] mySecondList = myFirstList myFirstList = ["smallish", "medium", "large", "x-large", "xx-large"] print(myFirstList) print(mySecondList)
myFirstList is assigned a completely new value in the third line. The assignment operator doesn’t modify the originally assigned list of strings at all. Therefore the print statements give the following:
[‘smallish’, ‘medium’, ‘large’, ‘x-large’, ‘xx-large’]
[‘small’, ‘medium’, ‘large’, ‘x-large’]
Modifications through direct access
In contrast to the above if you directly access parts of the object in memory it will affect any other variable that references that object. Consider the following dictionary-based example:
myFirstDictionary = {"S": "Small", "M": "Medium", "L": "Large", "XL": "X-Large"} mySecondDictionary = myFirstDictionary myFirstDictionary["S"] = "Smallish" myFirstDictionary["XXL"] = "XX-Large" print(myFirstDictionary) print(mySecondDictionary)
What do you think these print statements will give you? mySecondDictionary and myFirstDictionary point to the same dictionary object in memory. We directly access that dictionary object using the [] operator for dictionaries. mySecondDictionary will indeed also be affected by the direct change applied to myFirstDictionary:
{‘XXL’: ‘XX-Large’, ‘S’: ‘Smallish’, ‘L’: ‘Large’, ‘XL’: ‘X-Large’, ‘M’: ‘Medium’}
{‘XXL’: ‘XX-Large’, ‘S’: ‘Smallish’, ‘L’: ‘Large’, ‘XL’: ‘X-Large’, ‘M’: ‘Medium’}
Here’s a similar example using lists:
myFirstList = ["small", "medium", "large", "x-large"] mySecondList = myFirstList myFirstList[0] = "smallish" print(myFirstList) print(mySecondList)
…which gives…
[‘smallish’, ‘medium’, ‘large’, ‘x-large’]
[‘smallish’, ‘medium’, ‘large’, ‘x-large’]
It is very important for the programmer to keep in mind that if an object is mutable, i.e. can be modified directly like in the case of a dictionary or a list then any other variable referencing the same object will also be affected. Do not assume that the assignment operator ‘=’ somehow creates a copy as in mySecondList = myFirstList. mySecondList won’t magically be an independent copy of myFirstList that you can modify separately. myFirstList and mySecondList will point to the same object in memory with all its consequences. We’ll look at one of those consequences in the next post.
Read all Python-related posts on this blog here.
Reblogged this on Dinesh Ram Kali..