[python] generator生成器(斐波那契数列、杨辉三角)理解,log分析
认识generator
这里就不讲generator
的定义了,各种教程都有写,这里只记录一下我自己对于generator
的初学理解:
generator
函数的基本应用方向,当一组数据有一定的关联规则,就可以使用generator
来定义它的规则,以便根据规则和需求不断的生成数据generator
可以理解为是个对算法的包装,调用方式一般(简单的应用)是迭代,每次返回一个值,下次返回基于上次的值而计算出的值,直到迭代结束generator
的关键字是yield
,一个方法包含yield
,这个函数即为generator
对象。generator
方法中一般需要一个while
语句,用于不断产生满足条件的值、且当条件不满足时结束generator
的执行。在while
中,当执行到yield
,即会返回本次生成的值,本次执行到此为止;下次执行从yield
行之后开始执行,到while
中代码结束时并不会停止执行,将继续跳到while
内部开头位置,并执行到yield
,返回新生成的值才结束(下面有示例和log)
示例
1. 斐波那契数列
斐波拉契数列(Fibonacci),除第1个和第2个数外,任意一个数都是它前两个数相加的值:
1, 1, 2, 3, 5, 8, 13, 21, 34, …
代码
(注:为便于理解generator
的执行流程,以下代码实现并不是最优化的实现)
def fibonacci(maxTimes):
n = 1
a = 0
b = 1
temp = 0
print(f'(step 0) before while n = {n}; a = {a}; b = {b}; temp = {temp};')
while n <= maxTimes:
print(f'(step 1) in while before yield n = {n}; a = {a}; b = {b}; temp = {temp};')
yield b
print(f'(step 2) in while after yield n = {n}; a = {a}; b = {b}; temp = {temp};')
temp = b
b = a + b
a = temp
n += 1
print(f'(step 3) in while end n = {n}; a = {a}; b = {b}; temp = {temp};')
# Test
for s in fibonacci(9):
print(f'----- fibonacci-value = {s} -----')
print()
Log
(step 0) before while n = 1; a = 0; b = 1; temp = 0;
(step 1) in while before yield n = 1; a = 0; b = 1; temp = 0;
----- fibonacci-value = 1 -----
(step 2) in while after yield n = 1; a = 0; b = 1; temp = 0;
(step 3) in while end n = 2; a = 1; b = 1; temp = 1;
(step 1) in while before yield n = 2; a = 1; b = 1; temp = 1;
----- fibonacci-value = 1 -----
(step 2) in while after yield n = 2; a = 1; b = 1; temp = 1;
(step 3) in while end n = 3; a = 1; b = 2; temp = 1;
(step 1) in while before yield n = 3; a = 1; b = 2; temp = 1;
----- fibonacci-value = 2 -----
(step 2) in while after yield n = 3; a = 1; b = 2; temp = 1;
(step 3) in while end n = 4; a = 2; b = 3; temp = 2;
(step 1) in while before yield n = 4; a = 2; b = 3; temp = 2;
----- fibonacci-value = 3 -----
(step 2) in while after yield n = 4; a = 2; b = 3; temp = 2;
(step 3) in while end n = 5; a = 3; b = 5; temp = 3;
(step 1) in while before yield n = 5; a = 3; b = 5; temp = 3;
----- fibonacci-value = 5 -----
(step 2) in while after yield n = 5; a = 3; b = 5; temp = 3;
(step 3) in while end n = 6; a = 5; b = 8; temp = 5;
(step 1) in while before yield n = 6; a = 5; b = 8; temp = 5;
----- fibonacci-value = 8 -----
(step 2) in while after yield n = 6; a = 5; b = 8; temp = 5;
(step 3) in while end n = 7; a = 8; b = 13; temp = 8;
(step 1) in while before yield n = 7; a = 8; b = 13; temp = 8;
----- fibonacci-value = 13 -----
(step 2) in while after yield n = 7; a = 8; b = 13; temp = 8;
(step 3) in while end n = 8; a = 13; b = 21; temp = 13;
(step 1) in while before yield n = 8; a = 13; b = 21; temp = 13;
----- fibonacci-value = 21 -----
(step 2) in while after yield n = 8; a = 13; b = 21; temp = 13;
(step 3) in while end n = 9; a = 21; b = 34; temp = 21;
(step 1) in while before yield n = 9; a = 21; b = 34; temp = 21;
----- fibonacci-value = 34 -----
(step 2) in while after yield n = 9; a = 21; b = 34; temp = 21;
(step 3) in while end n = 10; a = 34; b = 55; temp = 34;
Process finished with exit code 0
观察log可以发现:
- (step 0) 只执行了1次,它在
generator
函数之中,且在while
语句之前 - 第一次,进入
while
,执行到且直接在yield
返回生成的第一个值,并在Test代码中打印结果 - 之后每次(除了最后一次),执行顺序都是 (step 2) ---- (step 3) ---- (step 1),并输出结果
- 最后一次,仅执行了**(step 2)** ---- (step 3),没有执行到**(step 1)**,也没有输出结果,因为
n > maxTimes
了,不再满足while
条件
2. 杨辉三角
杨辉三角如下:
1
/ \
1 1
/ \ / \
1 2 1
/ \ / \ / \
1 3 3 1
/ \ / \ / \ / \
1 4 6 4 1
/ \ / \ / \ / \ / \
1 5 10 10 5 1
- 每行开头、结尾数字都是1
- 每行其它数字都是它上行对应前后两数字之和(基于上图示)
代码
(注:为便于理解generator
的执行流程,以下代码实现并不是最优化的实现)
def triangles_yang(maxLines):
n = 1
list_line = [1] # 用于第一次返回1
while n <= maxLines:
yield list_line
# 以下为除第一次之外的每次的计算过程
pre_list_line = [1] # 开头1
for i, v in enumerate(list_line):
if 0 < i < len(list_line):
# 中间每一个数字是它上行对应前后两数字之和
pre_list_line.append(list_line[i - 1] + v)
pre_list_line.append(1) # 结尾1
list_line = pre_list_line # 赋值给list_line,用于下次计算
n += 1
# Test
for t in triangles_yang(12):
print(t)
Log
[1]
[1, 1]
[1, 2, 1]
[1, 3, 3, 1]
[1, 4, 6, 4, 1]
[1, 5, 10, 10, 5, 1]
[1, 6, 15, 20, 15, 6, 1]
[1, 7, 21, 35, 35, 21, 7, 1]
[1, 8, 28, 56, 70, 56, 28, 8, 1]
[1, 9, 36, 84, 126, 126, 84, 36, 9, 1]
[1, 10, 45, 120, 210, 252, 210, 120, 45, 10, 1]
[1, 11, 55, 165, 330, 462, 462, 330, 165, 55, 11, 1]