Section 6.5.2 of your text (pages 183 - 193) explain the concept of a mutator: a function that mutates one or more of its parameters. This document elaborates with examples.
In class we saw that functions can assign values to their formal parameters, e.g.:
def nextSquare(x):
x = x + 1
return x * x
But we also saw that the calling code cannot see the effect of this assignment:
y = 8 next = nextSquare(y) print("y is {}, next is {}".format(y, next)
The above prints:
y is 8, next is 81
This is because the assignment to x in the first line of the body of nextSquare() only changes the value referred to (or pointed to) by x. Informally, it just moves the post-it note for x onto the number 9, but the post-it note for y remains stuck to 8.
By the way, before we continue the discussion of mutators, note two detours:
def nextSquare(x): return (x + 1) * (x + 1)The first version of the nextSquare() function above uses poor style: it reassigns a parameter, which is a bit misleading because we think of parameters as coming “into” a function, and it is easier to reason about them if they keep the same value (sort of like an input from the user would). The second version avoids the bad style.
We used the first version just to make the point that the variable x is local to the function nextSquare().
Returning to our discussion of mutators, we've also seen that we can modify the CONTENTS of a list without using assignment:
squares = [] for n in range(10): squares.append(n ** 2) print(squares) # prints: # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
Here the append()
method tells the
squares
list to add the given square to its "tail". Informally, the
squares
post-it note remains stuck to the same list throughout the code, but the list is being
mutated by the append()
method.
We can also mutate a list by assigning to its individual elements:
numbers = [2,3,5,7,11]
for i in range(len(numbers)):
numbers[i] = numbers[i] ** 2
print(numbers)
# prints:
# [4, 9, 25, 49, 121]
In this example the
numbers
post-it note never moves once it is stuck to the original list. The assignment to
numbers[i]
in the body of the loop
mutates the list by changing elements inside it.
It might help to think of the list like an egg carton.
We put the numbers 2, 3, 5, 7, and 11 into the first five pockets of the egg carton,
then we affix the numbers
post-it note to the carton.
In the loop we take out each number and replace it with its square,
one pocket at a time. The carton and the post-it note never change.
We can use this idea of mutating a list to create a function that changes its parameters.
Here's a function that does just that:
def factEach(nums):
'''Replaces each element of nums with its factorial.'''
for i in range(len(nums)):
nums[i] = factorial(nums[i]) # factorial defined as in class
And some code demonstrating the function:
numbers = [2, 3, 5, 7, 11]
factEach(numbers)
print(numbers)
# prints:
# [2, 6, 120, 5040, 39916800]