I have a function score0
which gives me a score for every turn (for n
turns) in a loop. This score is incremented by a random integer from 1 to 15 every turn.
I now have to design another higher order function which should print the highest score jump of a player out of all the score jumps yet, and should be called inside the score0
function. I name it highest_gain
. Naturally, this should print the first score value as it's the first turn (hence it is the biggest jump).
# Function that defines the highest point jump in a score yet
import random
def highest_gain(previous_value, highest_point):
def say(score) :
if previous_value == 0:
print ('Biggest gain by player0 yet with',score,'points!')
return highest_gain(score, score)
gain = score - previous_value
if gain > highest_point:
print('Biggest gain by player0 yet with',score,'points!')
return highest_gain(score, gain)
return say
# Function that gives me a new score (incremented) every turn
def score0(n, score = 0):
while n > 0:
score = random.randint(1, 15)
highest_gain(previous_value = 0,highest_point = 0)(score)
n -= 1
return score
#Calling the function
score0(4,0)
The problem is that calling highest_gain()
doesn't update the values of previous_value
and highest_point
. Why aren't these variables getting updated in the score0()
function body, and how should highest_gain()
be called be called so that these variables are updated on each iteration of the loop?
CodePudding user response:
Your highest_gain
function is a higher-order function which returns another function named say
. When say
is called, it calls highest_gain
again and returns the result, which is - again - the function say
. The important point here is that say
is a closure over the local variables of the outer function highest_gain
, so each time highest_gain
is called you get a different instance of the say
function, with different values of the outer function's local variables.
Now, since calling say
returns another instance of say
which closes over the updated values, that means you need to keep the result from when you call it, so you can call the new instance which closes over those updated values.
def score0(n, score=0):
say = highest_gain(previous_value=0, highest_point=0)
while n > 0:
score = random.randint(1, 15)
say = say(score) or say
n -= 1
return score
I moved the original call of highest_gain
to before the loop, since you don't want to use the initial values of 0
on every iteration.
Note that say
doesn't always return a new instance of say
- sometimes it returns None
, so I used the trick say(score) or say
here so that say
keeps its old value if there isn't a new one to update it with. You could alternatively write this as below, which is more verbose but perhaps makes clearer what this is doing:
new_say = say(score)
if new_say is not None:
say = new_say
Otherwise, you could change the definition of say
so that it returns itself (i.e. with the current values of the variables from the outer function) when there should be no update, and then in score0
you could just write say = say(score)
.