日拱一卒,伯克利CS61A,两道题熟悉Python函数式编程

2022-08-26 14:31:27 浏览数 (1)

作者 | 梁唐

大家好,日拱一卒,我是梁唐。

我们今天继续来看伯克利CS61A的公开课,这次咱们聊聊hw02,也就是作业2。

这一次的作业关于Python函数式编程,其实哪怕是局限在Python语言当中,函数式编程也不是一个简单的概念。除了高阶函数之外,还有装饰器、偏函数、MapReduce等等许多内容。

但在日常使用当中,高阶函数的使用往往可以大幅提升代码质量,降低阅读难度,但大多数情况下并不是必须的。我不确定制定课程的教授是如何思考的,以我个人来看,作为初学者而言,了解函数式编程的思想以及它的使用场景,对这个概念熟悉起来,其实要比死记硬背一些所谓高端的用法更有用。

这一次的作业,刚好是一个非常好的用来学习、熟悉函数式编程思想的例子。

废话不多说,我们来看题。

首先,题目给定了一些代码,定义了一些函数。有常规函数,也有匿名函数。

代码语言:javascript复制
def square(x):
    return x * x

def identity(x):
    return x

triple = lambda x: 3 * x

increment = lambda x: x   1

add = lambda x, y: x   y

mul = lambda x, y: x * y

在Python当中,匿名函数以关键字lambda开头,后面跟函数的传参,冒号之后是函数的返回结果。在这种格式的限定下,使得匿名函数的逻辑往往不能太过复杂,只能用来解决一些简单的计算问题。

我们简单阅读一下代码,可以看到这几个函数的功能都非常简单。square是平方,identity就是返回本身,triple是乘3,increatment是自增1,add是两数相加,mul是两数相乘。

看完了这段代码之后,开始正式看题。

Q1: Product

课件当中有一个例子是函数summation(n, term),它是一个高阶函数,它返回term(1) term(2) ... term(m)的结果。

请你仿照summation函数,实现一个product函数,来实现term(1) * term(2) *...*term(n)

其中课件中的summation函数代码如下:

代码语言:javascript复制
def summation(n, term):
    """Sum the first N terms of a sequence.

    >>> summation(5, cube)
    225
    """
    total, k = 0, 1
    while k <= n:
        total, k = total   term(k), k   1
    return total

核心点在于term不仅是函数的传参,而且它本身就是一个可以调用的函数。所以只要搞清楚这点,代码非常好写:

代码语言:javascript复制
def product(n, term):
    """Return the product of the first n terms in a sequence.
    n    -- a positive integer
    term -- a function that takes one argument

    >>> product(3, identity)  # 1 * 2 * 3
    6
    >>> product(5, identity)  # 1 * 2 * 3 * 4 * 5
    120
    >>> product(3, square)    # 1^2 * 2^2 * 3^2
    36
    >>> product(5, square)    # 1^2 * 2^2 * 3^2 * 4^2 * 5^2
    14400
    >>> product(3, increment) # (1 1) * (2 1) * (3 1)
    24
    >>> product(3, triple)    # 1*3 * 2*3 * 3*3
    162
    """
    "*** YOUR CODE HERE ***"
    ret = 1
    for i in range(1, n 1):
        ret *= term(i)
    return ret
  
# The identity function, defined using a lambda expression!
identity = lambda k: k

我们仿照同样的逻辑,将加好改成乘号即可。

第二个问题是使用product函数实现阶乘函数factorial

代码语言:javascript复制
def factorial(n):
    """Return n factorial for n >= 0 by calling product.

    >>> factorial(4)
    24
    >>> factorial(6)
    720
    >>> from construct_check import check
    >>> check(HW_SOURCE_FILE, 'factorial', ['Recursion', 'For', 'While'])
    True
    """
    "*** YOUR CODE HERE ***"
    return product(n, identity)

我们只需要依照逻辑,让n个整数依次相乘即可。我们可以传入函数identity,因为identity(x)=x

Q2: Make Adder with a Lambda

实现make_adder函数,它返回一个lambda表达式。

本题就是lambda表达式的基本使用,了解函数式编程之后,也很简单。

代码语言:javascript复制
def make_adder(n):
    """Return a function that takes an argument K and returns N   K.

    >>> add_three = make_adder(3)
    >>> add_three(1)   add_three(2)
    9
    >>> make_adder(1)(2)
    3
    """
    "*** YOUR CODE HERE ***"
    return lambda x: x   n

对于返回的函数lambda x: x n而言,这里的参数n的定义在它的外部。这里涉及到Python当中一个很重要的概念叫做——闭包,闭包的原理和应用也是函数式编程中的一个范畴。

大家要是感兴趣可以去研究一下,这里不做过多的展开了。

本次作业的代码已经上传到了GitHub,感谢大家的阅读。

0 人点赞