[Tutor] Tuples, Dictionarys and mutable vs. immutable

Danny Yoo dyoo@hkn.eecs.berkeley.edu
Mon, 26 Feb 2001 01:23:49 -0800 (PST)


On Sun, 25 Feb 2001, Sheila King wrote:

> OK, now I'm really confused.
> 
> I don't really "get" the difference yet, between mutable and immutable
> types, but I figured I would eventually get it. But at least I thought
> I understood that an object could not change its type or its id. At
> least I thought I understood that.

I'll try to help explain the mutable/immutable system that Python's uses,
and perhaps this will make things clearer.  This message will be long
because of all the pretty ASCII graphics.  *grin*

Python uses a name-object methodology; that is, when we type something
like this:

###
>>> x = 5
>>> y = x
###

we have the following curious picture:

x -------> 5
           ^
           |
y ---------|

We call "x" and "y" the references to the value 5.  Whenever we write a
number, Python creates a number value, and we can imagine that it floats
around in space, tied to the ground only by our references.  The value 5
will stick around until we cut loose both x and y.  That is, if we do:

###
>>> del x
>>> y
5
###

we can see that 'y' is still attached to the value '5'.  Intuitive enough.

The idea about immutability involves the following problem: what happens
when we begin to manipulate our variables, through addition,
multiplication, or anything else?  For example, what happens here?

###
>>> x = 3          # (a)
>>> y = x          # (b)
>>> x = x + y      # (c)
###

At step (a), we create a value 3, and name it 'x'.  Then, we direct our y
reference to the same thing.  There's no problem there, since we'd expect
x and y to be both 3.  Step (c) might be weird, depending on your
background.  Let's draw out what it looks like:


(before assignment)       (doing the right hand side)
x------>3                     (rhs)---->6
        ^                 
y-------|                      x---->3
                                     ^
                               y-----|


(finally directing x to this new right hand side)
               x------>6
               y------>3


By immutability, we mean that whenever we start manipulating a immutable
item, Python will spawn off another value for us; it leaves the original
value intact.  Changing the value that 'x' is directed to will not affect
'y', because they're directed at two distinct values.

The same thing goes for tuples and string --- the only way we can
manipulate these immutable values is to create whole new values.  That's
why strings don't allow arbitrary index assignment, to make things a
little easier to work with.  For example, when we do this:

###
>>> mystr1 = "hello world"
>>> mystr2 = mystr1
>>> mystr1 = mystr1[:-1]
>>> mystr1
'hello worl'
>>> mystr2
'hello world'
###

whatever we did to mystr1 doesn't affect mystr2, because they're pointed
to distinct values.  Taking slices of strings, in affect, will create a
whole new string.  If you've worked with other programming languages,
(like C, for example), you'll notice a big difference!



That introduces immutability; immutable values can't be changed, and
manipulating them results in creating whole new values.  Now that we sorta
know about immutable types, what does it mean to be mutable?  In this
case, values CAN change.

Lists are mutable, so let's take a look at them.  When we do this:

###
>>> mylist = range(4)
>>> samelist = mylist
>>> mylist
[0, 1, 2, 3]
>>> samelist
[0, 1, 2, 3]
###

we get this picture:

mylist--------> [1, 2, 3, 4]
                ^
                |
samelist--------|


Same thing as when we were working with numbers.  However, let's see what
happens here:

###
>>> mylist.append(4)
>>> mylist
[0, 1, 2, 3, 4]
###

Mutable types allow their values to change.  What our picture now shows is
this:

mylist--------> [1, 2, 3, 4, 5]
                ^
                |
samelist--------|

and we can confirm this!

###
>>> samelist
[0, 1, 2, 3, 4]
###

That's what we mean by immutable types; the manipulations that we make
with them have the potential for changing the value.  If two references
point to the same value, then, we need to realize that changing the value
will reflect on both references.

This is not to say that we can't spawn off new copies of a mutable
value.  That's what list slicing is for.  As soon as we do this:

###
>>> samelist = mylist[:]
###

Python will create a whole new list, populated with the values of mylist:

mylist--------> [1, 2, 3, 4, 5]
samelist------> [1, 2, 3, 4, 5]

which means that we can mangle mylist with reckless abandon, without
having to worry about the stability of samelist:

###
>>> del mylist[0]
>>> mylist[0], mylist[3] = mylist[3], mylist[0]
>>> mylist
[4, 2, 3, 1]
>>> samelist
[0, 1, 2, 3, 4]
###



> Then, explain this from my Python IDLE:
> Python 2.0 (#8, Oct 16 2000, 17:27:58) [MSC 32 bit (Intel)] on win32
> Type "copyright", "credits" or "license" for more information.
> IDLE 0.6 -- press F1 for help
> >>> mytuple = 'a', 'b', 'c'
> >>> mytuple
> ('a', 'b', 'c')
> >>> type (mytuple)
> <type 'tuple'>
> >>> mytyple = 'b'
> >>> mytyple
> 'b'
> >>> type (mytyple)
> <type 'string'>
> >>> mytuple = mytyple
> >>> type (mytuple)
> <type 'string'>

> mytuple is originally a tuple. And then I end up changing it to a
> string? I thought this was not possible.

Immutable values themselves cannot change.  However, we can direct our
references, these names, back and forth from one value to another without
restriction:

###
>>> a, b = 'one', 1 
>>> b, a = a, b
>>> a
1
>>> b
'one'
>>> a, b = b, a
>>> a
'one'
>>> b
1
###

Back and forth.  *grin*  It IS a little weird though, so don't worry if it
doesn't make too much sense yet.

If you have any questions, please feel free to ask.