==[Below is Mutability.txt - one of the "new" files Diane sent last time] = Mutability = == Introduction == - We said that a variable is a name and a value associated with it, and that every variable has a type. - There are two big categories of types: things you can change and things you can't ... - This has a big impact on how programs behave, we we need to understand it. Fortunately, the memory model will be a big help. == Mutable and immutable == - some types of Python objects are unchangeable Eg x = 3 x = 5 # We can't change a 3; it is what it is. We just make # x refer to a new integer object. [Trace this in the memory model.] - other types of Python objects are changeable Eg pic = media.load_picture(filename) for pixel in picture: media.set_blue(pixel, new_blue) # pic still refers to the same picture object, # but something about it has changed [Trace this in the memory model.] - we say that objects are "mutable" or "immutable" (The word "mutable" comes from the same root as "mutate") == Testing your understanding == - QU: what is the output from this? a = 19 b = a a = 42 print a, b - QU: what does pic2 look like after this? a = media.load_picture(file) b = a for pixel in a: media.set_green(pixel, 0) media.show(b) - Notice the similarity: In both cases we set b to a and then change a But the big difference: With the int variables, changing a has no effect on b QU: Why? (Because a and b refer to different int objects!) With the picture variables, changing a effects b QU: Why? (Because a and b refer to the same picture object) == Mutable and immutable parameters == - Remember that passing a parameter is like an assignment statement. - So the issue we just saw with ordinary assignment comes up with parameter passing too. - When you have a mutable parameter, you can make changes to the object it refers to. They will therefore be changes to the object that the argument refers to, since they both refer to the same thing. Eg def make_red(picture): for pixel in picture: ... media.set_blue(pixel, new_blue) ... if __name__ == '__main__': pic = ... make_red(pic) - pic and picture both refer to the same picture object. So when we change the object that picture refers to, we are changing the object that pic refers to - Implication: there is no need to return the revised picture. - But when you have an immutable parameter, the same idea won't work Eg [CODE: immutable.py] def double(x): x = x * 2 if __name__ == '__main__': x = 27 double(x) print x - Doesn't work! QU: Why not? Double's x and main's x start out referring to the same object. But you can't change an int, so x = x * 2 creates a new int object. Now double's x and main's x refer to two different objects. Changing what double's x refers to had no effect on main's x. [Trace in memory model. Note the two different x's.] - So how do we make this code work? The only way to have an effect where the function was called, is to return a value (and the caller can then make one of its variables refer to that) - Let's fix it: def double_fixed(x): return x * 2 if __name__ == '__main__': x = 27 x = double_fixed(x) print x