|
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()
'HOMER'
>>> name
'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()
>>> li
[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
'Homer'
>>> name = name.upper()
>>> name
'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
>>>
| |
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')
>>> sports
['baseball', 'soccer', 'golf', 'football']
>>> sports[2] = 'tennis'
>>> sports
['baseball', 'soccer', 'tennis', 'football']
| |
|
>>> fruits = {'a':'apple', 'b':'banana', 'c':'carrot'}
>>> fruits['c'] = 'cherry'
>>> 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'
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')
| |
|