elarson’s posterous

 
« Back to blog

Seriously Mutable

I ran into this today and wanted to write it down somewhere both for myself and posterity (ok, mostly for myself).

As you may know, python dictionaries are mutable. This means you can do things like this:



x = {'foo':'bar'}

def change_it(d, new_value):
    d['foo'] = new_value

change_it(x, 'baz')
print x # should print {'foo': 'baz'}


As you can see, the variable x can be changed anywhere. With that in mind what I was doing was basically this:



x = {'foo': 'bar'}

def change_it(new_value):
    y = x['foo']
    y = new_value


change_it('baz')
print x # we get {'foo': 'bar'} as expected


So, this might give you the impression that when you access a value in a dictionary that value is not a reference to the original. But, what about this?



x = {'foo': {1: 'one'}}

def change_it(new_value):
    y = x['foo']
    y.update(new_value)


change_it({2: 'two'})
print x     # do you expect {'foo': {1: 'one'}} ?


You will actually get:

{'foo': {1: 'one', 2: 'two'}}

The reason this happens is because the reference you get back is a mutable object, so in the above code, the variable "y" points to the same mutable dict "x['foo']" points to. We can test this with this bit of code:



x = {'foo': {1: 'one'}}
y = x['foo']
print y is x['foo'] # True


When you consider python always passes by reference this makes sense. At the same time, it can be a little sneaky if you're not thinking about it since it is usually pretty simple to just use code like "y = x['foo']" and expect it to act like a copy.

Thanks to a few folks in #cherrypy on oftc.net for clearing up my explanation on this.