一、题目描述
先看来自于 廖雪峰老师的一道 Python 练习题
杨辉三角定义如下:
1/ \1 1/ \ / \1 2 1/ \ / \ / \1 3 3 1/ \ / \ / \ / \1 4 6 4 1/ \ / \ / \ / \ / \
1 5 10 10 5 1
把每一行看做一个list,试写一个generator,不断输出下一行的 list:
def triangles():pass# 期待输出:
# [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]
n = 0
results = []
for t in triangles():results.append(t)n = n + 1if n == 10:breakfor t in results:print(t)
二、思路分析
我们先从第二行开始,看一下更通用的序列生成过程:
1、首尾两个元素固定是1
2、下一行的序列生成依赖于上一行
3、下一行实际需要生成的元素个数,是上一行序列长度-1
就比如
[1,1] -> [1,2,1] L = [1,1] 2 = L[0]+L[1] result = [1]+[2]+[1]=[1,2,1] 需要生成 2 一个元素
L = [1,1]
result = [1]
# 只需要循环一次
for i in range(len(L)-1):result.append(L[i]+L[i+1])
result.append(1)
print(result)
[1,2,1] -> [1,3,3,1] L = [1,2,1] 3 = L[0]+L[1] 3 = L[1]+L[2] result = [1]+[3,3]+[1] 需要生成 3,3 两个元素
L = [1, 2, 1]
result = [1]
# 需要循环两次
for i in range(len(L)-1):result.append(L[i]+L[i+1])
result.append(1)
print(result)
仔细观察,这段代码,是不是可以简写成 列表生成式?
L = [1,1]
print( [1] + [ L[i]+L[i+1] for i in range( len(L)-1 ) ] + [1] )
L = [1,2,1]
print( [1] + [ L[i]+L[i+1] for i in range( len(L)-1 ) ] + [1] )
由此,我们得到一个从上一行序列生成下一行序列的,通用的表达式:
L = 上一行列表
[1] + [ L[i]+L[i+1] for i in range( len(L)-1 ) ] + [1]
从 [1] -> [1,1] 是否也符合这个表达式呢?
考虑到 for i in range(0) 循环是不执行的
for i in range(0):print(i)
所以,L = [1] result = [1]+[]+[1]=[1,1] 也是符合我们表达式的。
L = [1]
print( [1] + [ L[i]+L[i+1] for i in range( len(L)-1 ) ] + [1] )
L = [1,1]
print( [1] + [ L[i]+L[i+1] for i in range( len(L)-1 ) ] + [1] )
L = [1,2,1]
print( [1] + [ L[i]+L[i+1] for i in range( len(L)-1 ) ] + [1] )
至此,除了杨辉三角的第一行序列 [1],我们得到了一个通用的表达式,第一行序列 [1],就让它直接返回就好。
L = [1] 返回
从第二行开始
L = 上一行序列
L (下一行序列) = [1] + [ L[i]+L[i+1] for i in range( len(L)-1 ) ] + [1]
三、generator 写法
我们把上面的思路,用 generator 函数语法写出来:
def triangles():L = [1]while True:# 第一次调用 next,保留函数现场 L=[1] 返回 [1]yield L# 第二次调用 next,从这里开始,取出函数现场 L=[1] 执行,然后循环# 直到碰到 yield 关键字,继续保留函数现场,然后返回L = [1] + [ L[i]+L[i+1] for i in range( len(L)-1 ) ] + [1]n = 0
results = []
for t in triangles():results.append(t)n = n + 1if n == 10:breakfor t in results:print(t)