CS61A——高阶函数
纲要
- 迭代例子
- 设计函数
- 一般化
- 高阶函数
- lambda表达式
- 条件表达式
迭代例子
维拉汉卡-斐波那契数字
1 | 0 1 1 2 3 5 8 13 21 34 |
从第三个数开始,每个数都等于前两项的和。
维拉汉卡问题
对于一个总时长有多少种节奏存在?
S表示短音节,L表示长音节,一个长音节等于两个短音节。
时长 | Meters | 总可能性 |
---|---|---|
1 | S | 1 |
2 | SS,L | 2 |
3 | SSS,SL,LS | 3 |
4 | SSSS,SSL,SLS,LSS,LL | 5 |
5 | SSSSS,SSSL,SSLS,SLSS,SLL,LLS,LSL,LSSS | 8 |
斐波那契问题
一对兔子每个月可以生一对兔子,N个月后有多少对兔子?
维拉汉卡-斐波那契数字生成
1 | def vf_number(n): |
这里用了个循环来解决。
黄金螺旋
黄金螺旋也可以近似看做维拉汉卡-斐波那契数列。
据说熊身上都有黄金螺旋,多少有点强行了。
设计函数
描述函数
1 | def square(x): |
Aspects | Examples |
---|---|
一个函数的域(domain)是通过参数得到的所有输入的集合 | x 是一个数 |
一个函数的范围(range)是其返回的输出的值的集合 | square 返回一个非负实数 |
一个纯函数的行为(behavior) | square 返回x 的平方 |
定义一个函数
只给一个函数一个工作,但让其适应很多相关情形:
1 | round(1.23) # 1 |
别自己重复(DRY,Don’t Repeat Yourself):只实现一个过程,执行很多次。
一般化
通过参数一般化模式
几何形状有相似的面积公式:
一个非一般化的方法
1 | from math import pi, sqrt |
怎么一般化共同结构呢?
一般化的面积函数
1 | from math import pi, sqrt |
高阶函数
什么是高阶函数
满足两者之一的函数都是高阶方程:
- 以其他函数为参数;
- 返回一个函数作为它的结果;
其他函数都认为是一阶方程。
计算过程上的一般化
函数间的共同结构可能是一个计算过程,而不止是一个数,比如:
函数作为参数
1 | def cube(k): |
函数作为返回值
局部定义的函数
定义在其他函数体内的函数会绑定到局部帧的命名。
1 | def make_adder(n): |
调用表达式作为操作符表达式
1 | make_adder(1)(2) |
make_adder(1)
调用了函数,返回了一个函数又作为函数被调用。
Lambda表达式
lambda语法
lambda表达式是一种简单的函数定义,计算结果是一个函数,语法为:
1 | lambda <parameters>: <expression> |
返回的函数以parameters
为输入并返回expression
计算的值。
比如,lambda版本的square
函数:
1 | square = lambda x: x * x |
会返回一个函数,以x
为参数,返回x * x
作为结果。
Lambda语法提示
lambda表达里面不应该包含return语句,如:
错误用法:
1 | square = lambda x: return x * x |
def
语句和lambda
表达式对比
1 | # def语句 |
共同点:
- 都创建了一个函数,域、范围和行为都一样;
- 都把函数绑定到了
square
上;
不同点:
只有def
语句给了函数一个固有名称,可以在环境图中看到,但不影响执行,只在打印的时候有区别。
lambda作为参数
要把简单函数作为参数的时候用lambda表达式很方便:
1 | # 原始方法 |
条件表达式
条件表达式
条件表达式格式如下:
1 | <consequent> if <predicate> else <alternative> |
规则是这样的:
- 求
<predicate>
的值; - 如果值为真,整个表达式的值为
<consequent>
; - 否则,表达式的值为
<alternative>
。
有条件表达式的lambda语句
错误语法:
1 | lambda x: if x > 0: x else: 0 # 不能有冒号 |
正确语法:
1 | lambda x: x if x > 0 else 0 |