Cool Computer Science Thing of the Day
Reading Questions
Quiz
Mutability
In the last lab we generated a list of random numbers by doing the following
numbers = [] for i in range(SIZE): numbers += [random.randrange(SIZE)]
- This is just like what we did with strings, create a new list by repeatedly adding on to the end
- One thing to note though is that it creates a new list every time
- With strings we had to do this, but strings are immutable
Lists, however, are mutable, we can change them
numbers = [] for i in range(SIZE): numbers.append(random.randrange(SIZE))
- This adds a new element to the end of the list, without creating a new one
- This code is functionally equivalent, but it is more effiecient
Caution: one common error with mutability is removing from a list while iterating over it
numbers = [1, 3, 2, 1, 3, 2, 1] for i in range(len(numbers)): if numbers[i] == 1: del numbers[i]
- This is because the range function is executed only once, before the loop is run
To fix, could use a while loop, that checks the condition after every iteration or could iterate backwards
Aliasing
- Lists being mutable has a few consquences
With strings
a_string = 'spam' b_string = a_string print(a_string, b_string) b_string = a_string + ' is delicious' print(a_string, b_string)
- Changing one string does not affect the other because the concatenate creates a new string
Lists on the other hand
a_list = [1, 2, 3] b_list = a_list print(a_list, b_list) b_string.append(-1) print(a_list, b_list)
- Changing on list affects another list because append does not make a copy, it modifies
- This is called aliasing, and would be simple to avoid if it only occured when you assign on list to another
- Note, if you did need one list to be equivalent to another, without aliasing you can make a copy with a slice
This also happens every time you call a function with a list as a parameter
def a_func(b_list): b_list.append(-1) a_list = [1, 2, 3] a_func(a_list) print(a_list)
- This is desirable sometimes
A function can modify a list instead of returning a list, which can be more efficient than copying the entire list to make a small change
Sprites
- One other example of mutability, sprites
I also created a module to make doing some of common things with the graphics module easier
import graphics import sprite a_sprite = sprite.Sprite(0, 0, 'sprite.gif') while graphics.window_open(): graphics.clear() graphics.draw_sprite(a_sprite) graphics.wait()
- Similar to the turtle module, you create sprite objects
- The graphics module can draw a sprite
- Note, the location of the sprite is an attribute of the sprite
You can change the attributes of a sprite using the dot notation
a_sprite.y += 1
- Sprites are mutable, which means that functions can modify them
This makes it much easier to organize you code
def update_sprite(a_sprite): a_sprite.y += 1
- You can also add your own attributes
For example the speed of a sprite could be an attribute
def update_sprite(a_sprite): a_sprite.y += a_sprite.speed_y a_sprite.speed_y = 1 a_sprite = sprite.Sprite(0, 0, 'sprite.gif')
This is useful for adding gravity, an acceleration
def update_sprite(a_sprite): a_sprite.speed_y += GRAVITY a_sprite.y += a_sprite.speed_y a_sprite = sprite.Sprite(0, 0, 'sprite.gif') a_sprite.speed_y = 0 while graphics.window_open(): graphics.clear() update_sprite(a_sprite) graphics.draw_sprite(a_sprite) graphics.wait()
Also have useful methods for testing for and handling collision
if a_sprite.collides(b_sprite): a_sprite.speed_y = 0 a_sprite.uncollide(b_sprite)