[CS61A-Fall-2020]学习记录五 Project1 The Game of Hog 中有意思的点

首先,本文不是总结归纳,只是记录一些有趣的知识点罢了

此外,观前提示,请最好在尝试独立完成该任务后再看本文,否则就很可能失去了体验本项目精华的机会

函数参数前的*

在项目原文件中的dice.py 里的 make_test_dice函数采用这样的方式传参

def make_test_dice(*outcomes):
  # 省略内容
  pass

我记得python中没像c那样的指针,于是查询资料,小结如下
函数参数前一颗*会识别为元组,两颗则识别为字典

比如我要是传 make_test_dice(1, 2, 4, 3),outcomes就是元组(1, 2, 4, 3)

举一个稍微复合一点点的例子

def foo(a, b=10, *args, **kwargs):
    print (a)
    print (b)
    print (args)
    print (kwargs)

foo(1, 2, 3, 4, e=5, f=6, g=7)

上述例子来自菜鸟教程,运行结果为

1
2
(3, 4)
{'e': 5, 'f': 6, 'g':7}

可发现除了定好的a、b,c和d都纳入元组中,而efg有=赋值,作为字典看待

上面的例子都发生在定义函数参数列表,如果在调用时有*说明什么呢?

再看一个例子

def func(num1, num2):
  print(num1, num2)

num = [1, 2]
func(*num)

运行结果为

1 2

一个参数变两,*在这里起到了解压参数列表的作用
但笔者尚未想到该功能应用的方便之处

Higher Order Function 高阶函数

这是一个让陆爻齐觉得十分精妙的功能,以函数为参数并返回函数,从 C 初学者的角度来说,太抽象了

就是在 Problem 7 的答案代码


def announce_highest(who, last_score=0, running_high=0):
    """Return a commentary function that announces when WHO's score
    increases by more than ever before in the game.

    NOTE: the following game is not possible under the rules, it's just
    an example for the sake of the doctest

    >>> f0 = announce_highest(1) # Only announce Player 1 score gains
    >>> f1 = f0(12, 0)
    >>> f2 = f1(12, 9)
    9 point(s)! The most yet for Player 1
    >>> f3 = f2(20, 9)
    >>> f4 = f3(20, 30)
    21 point(s)! The most yet for Player 1
    >>> f5 = f4(20, 47) # Player 1 gets 17 points; not enough for a new high
    >>> f6 = f5(21, 47)
    >>> f7 = f6(21, 77)
    30 point(s)! The most yet for Player 1
    """
    assert who == 0 or who == 1, 'The who argument should indicate a player.'
    # BEGIN PROBLEM 7
    "*** YOUR CODE HERE ***"
    def say(new_score_0, new_score_1, last_running_high = running_high):
        if who == 0:
            new_score = new_score_0
            new_running_high = new_score_0 - last_score
        else:
            new_score = new_score_1
            new_running_high = new_score_1 - last_score

        if new_running_high > last_running_high:
            last_running_high = new_running_high
            print(str(new_running_high),"point(s)! The most yet for Player " + str(who))
        
        new_run_high = last_running_high
        
        return announce_highest(who, new_score, new_run_high)
        
    return say
    # END PROBLEM 7

这段代码就是记录玩家 1 或 2 分数变化的幅度,并在最大幅度记录更新时 print 的函数。

传统函数(指 C/C++ 这种)要实现这种记录更新,必须在外部存储,用类或者其它外部变量什么的,因为函数一旦执行完毕,内部空间将全部释放。

下面对该代码做点拆解,忽略 say 的内容、断言、测试和注释,可看成


def announce_highest(who, last_score=0, running_high=0):
    # BEGIN PROBLEM 7
    "*** YOUR CODE HERE ***"
    def say(new_score_0, new_score_1, last_running_high = running_high):
        pass
        
    return say
    # END PROBLEM 7

可见,调用 announce_highest 的本质是获取到一个 say 函数,每次调用 say 函数,我们都期待它能检测是否要更新记录,而不断地更新最大幅度,则要不断地获取并调用 say 函数,那让 say 返回获取 say 函数的函数就解决了这个问题,即下面代码


def announce_highest(who, last_score=0, running_high=0):
    # BEGIN PROBLEM 7
    "*** YOUR CODE HERE ***"
    def say(new_score_0, new_score_1, last_running_high = running_high):
 
        pass

        return announce_highest(who, new_score, new_run_high)
        
    return say
    # END PROBLEM 7

再看测试代码就清晰多了

>>> f0 = announce_highest(1) # Only announce Player 1 score gains 这里的 f0 实际上是 who 为 1 时的 say 函数

>>> f1 = f0(12, 0) f1 的本质是代入 new_score_0 = 12 和 new_score_1 = 0 的 say 函数执行后,返回的新的 say 函数。你问 announce_highest 去哪了?announce_highest 也返回的 say 函数,只是没有参数代入的 say 函数而已

其它测试语句以上述类推

后面在 geek for geek 进行了更深入的学习,发现此前在 LALC 用的迭代器就是高阶函数的运用

posted @ 2024-07-18 00:57  陆爻齐  阅读(23)  评论(0编辑  收藏  举报