A lesson in copying and mutability -- the ability to change an object as it gets passed around, rather than changing a copy of an object you want to pass around.
I'm working the Computing the Average exercise. In the previous Sum of Scores exercise, I figured I could get away with a clever trick with the while loop:
def grades_sum(scores): result = 0 while len(scores)>0: result += scores.pop() return result
.pop() provides the neat function of taking the last item on a list and returning it to you. It also removes that item from the list itself. In a vacuum, this works great. But if you need to do something else, like compute the average, you've ruined the content of the
grades object itself because none of the scores are there anymore!
def grades_average(scores): denominator = float(len(scores)) numerator = grades_sum(scores) return numerator/denominator
Looks fine, right? The function call even returned and printed the right value, but I get the following validation error:
Oops, try again grades should contain [100, 100, 90, 40, 80, 100, 85, 70, 90, 65, 90, 85, 50.5]!
Turns out that my
grades_sum() function was changing the core content of grades itself! I got around it using
copy.deepcopy() (study up to understand why: Python docs 8.17 copy) but it might be worthwhile if the Sum of Scores exercise validated that the content of
grades didn't change once the sum was computed. The accepted answer is below:
from copy import deepcopy ... def grades_average(scores): destroyer = deepcopy(scores) denominator = float(len(scores)) numerator = grades_sum(destroyer) return numerator/denominator