高阶函数中变量作用域的概念理解

Conceptual understanding of variable scope in higher order functions

我有一个函数 score0,它在一个循环中为我提供每个回合(n 回合)的分数。这个分数每回合增加一个从 1 到 15 的随机整数。

我现在必须设计另一个高阶函数,它应该打印出所有跳跃得分中玩家的最高得分跳跃,并且应该在 score0 函数中调用。我把它命名为highest_gain。自然地,这应该打印第一个得分值,因为它是第一轮(因此它是最大的跳跃)。

# 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)

Python Tutor link

问题是调用 highest_gain() 不会更新 previous_valuehighest_point 的值。为什么这些变量没有在 score0() 函数体中更新,应该如何调用 highest_gain() 以便在循环的每次迭代中更新这些变量?

您的 highest_gain 函数是一个高阶函数,return 是另一个名为 say 的函数。当调用 say 时,它会再次调用 highest_gain 并得到 return 结果,即 - 再次 - 函数 say。这里的要点是 say 是外部函数 highest_gain 局部变量的 closure,所以每次 highest_gain 被调用时你都会得到 highest_gain 的不同实例=13=] 函数,外部函数局部变量的值不同。

现在,由于调用 say return 的另一个实例 say 关闭了更新的值,这意味着您需要保留调用它时的结果,所以您可以调用关闭这些更新值的新实例。

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

我将 highest_gain 的原始调用移到了循环之前,因为您不想在每次迭代时都使用 0 的初始值。

请注意 say 并不 总是 return say 的新实例 - 有时它 returns None,所以我在这里使用了 say(score) or say 技巧,这样 say 在没有新值更新时会保留其旧值。您也可以像下面这样写,它更冗长但可能更清楚这是在做什么:

new_say = say(score)
if new_say is not None:
    say = new_say

否则,您可以更改 say 的定义,使其 return 本身(即使用外部函数的变量的当前值)在不应该更新的情况下,并且然后在 score0 你可以只写 say = say(score).