Go to: Na-Rae Han's home page  

Python 3 Notes

        [ HOME | LING 1330/2330 ]

Mutability

<< Previous Note           Next Note >>
On this page: mutability, returning a value vs. in-place modification, tuples

Returning a New Value vs. Modifying Existing Value

Suppose you want to uppercase a string. You would use the .upper() string method. But calling the method on the original string does not change it:
 
>>> name = 'Homer'
>>> name.upper()      # returns 'HOMER'
'HOMER' 
>>> name              # unchanged
'Homer' 
What happens is that name.upper() creates and returns a new string value: the uppercased string 'HOMER'. You can see this return value spit out on the screen (in shell environment only). The original string name itself remains unchanged.

Contrast that with the behavior below. You have a list, and you reverse it by calling .reverse() method:
 
>>> li = [1, 2, 3, 4]
>>> li.reverse()          # nothing gets returned
>>> li                    # changed!
[4, 3, 2, 1] 
First off, calling li.reverse() does not return anything: note that the shell quietly goes back to the prompt. Secondly, the original list li itself has changed! That is because list methods such as .reverse() change the caller object in place: they modify the calling object directly in memory. This property is what makes certain data types, including list, mutable.

Immutable objects, by contrast, do not change through a function. Below, calling .upper(), .replace(), + , etc. all return a new string, and the original string remains unchanged. The only way to change the value of name is through issuing a new assignment statement. Because name.upper() returns a value, the variable name gets newly assigned to it.
 
>>> name = 'Homer'
>>> name.upper()
'HOMER' 
>>> name.replace('o', 'oooo')
'Hoooomer' 
>>> name + ' Simpson'
'Homer Simpson' 
>>> name              # still unchanged
'Homer' 
>>> name = name.upper()     # new assignment
>>> name                    # new value
'HOMER' 
What if you tried something similar with a list, a mutable type? Here's what happens: because li.reverse() reverses the list in place and RETURNS NOTHING, the last variable assignment will assign li to..., well, nothing. So, no, don't do this.
 
>>> li = [1, 2, 3, 4]
>>> li.reverse()
>>> li
[4, 3, 2, 1] 
>>> li = li.reverse()          # li.reverse() returns NOTHING
>>> li                         # So, li is now assigned to NOTHING
>>> 

Mutable: list, dictionary

So, what's mutable? Lists and dictionaries are. It makes sense: lists and dictionaries are something that needs constant changing -- growing, shrinking, updating and deleting entries, etc. The examples below further illustrate how list and dictionary values are modified in place.
 
>>> sports = ['baseball', 'soccer', 'golf', 'pinball', 'football']
>>> sports.remove('pinball')          # removing item
>>> sports
['baseball', 'soccer', 'golf', 'football'] 
>>> sports[2] = 'tennis'             # changing 3rd item
>>> sports
['baseball', 'soccer', 'tennis', 'football'] 
 
>>> fruits = {'a':'apple', 'b':'banana', 'c':'carrot'}
>>> fruits['c'] = 'cherry'            # changing value for 'c' key
>>> fruits
{'a': 'apple', 'c': 'cherry', 'b': 'banana'} 

Immutable: integer, float, string, tuple

The remaining data types are immutable: integers, floats, strings, and, tuples. Here's another example showing how strings are immutable. You cannot change the first character of 'bell' into 'c':
 
>>> wd = 'bell'
>>> wd[0] = 'c'         # trying to turn it into 'cell'

Traceback (most recent call last):
  File "<pyshell#99>", line 1, in <module>
    wd[0] = 'c'
TypeError: 'str' object does not support item assignment 
Now let's talk tuples. The whole point of tuples is that they are just like a list but immutable. Why is that necessary? Because lists grow and shrink, creating a list involves reserving a large block in the memory to accommodate its potential size. Tuples do not require such memory-side considerations. Therefore, for a list-like data that you know won't ever change, using a tuple is the smart thing to do. Below illustrates how tuples cannot be modified. Again, if you do need to change a tuple, you have to invoke a whole new assignment statement.
 
>>> seasons = ('Spring', 'Summer', 'Fall', 'Winter')
>>> seasons[2]
'Fall' 
>>> seasons[2] = 'Autumn'

Traceback (most recent call last):
  File "<pyshell#106>", line 1, in <module> 
    seasons[2] = 'Autumn'
TypeError: 'tuple' object does not support item assignment
>>> seasons = ('Spring', 'Summer', 'Autumn', 'Winter')
>>> seasons
('Spring', 'Summer', 'Autumn', 'Winter')