九九乘法,兔子数列,杨辉三角|用Python生成器的妙解

很多同学还是对生成器的用法,感到怀疑,特别是有其他语言基础的同学,一下子很难理解和转换过来,那什么情况下会用到yield,建议是当需要在循环过程中依次处理一个序列中的元素的时候,就应该考虑生成器,其实yield是非常巧妙而且很高效,一旦用习惯了就会事半功倍.

下面举几个简单的例子,让大家轻松理解生成器的妙用

一.九九乘法表

1.九九乘法表应该是耳熟能详的,我们用这个做第一个例子

def table_9_9(max=9):
   n=1
   while n<=max:
      N=['{}*{}={}'.format(i,n,n*i) for i in range(1,n+1)]
      n+=1
      print N
table_9_9()

打印输出一下:

《九九乘法,兔子数列,杨辉三角|用Python生成器的妙解》

2.这样只能打印,不能保存,而且上面还会有一个None(仔细看上面图的最下方)如果想保存状态,需要额外的加一个列表来保存
比如这样:

def table_9_9(max=9):
   n=1
   L=[]
   while n<=max:
      N=['{}*{}={}'.format(i,n,n*i) for i in range(1,n+1)]
      n+=1
      L.append(N)
   return L
T=table_9_9()
for t in T:
   print t

3.但是用生成器就可以很简单的搞定

def table_9_9(max=9):
   n=1
   while n<=max:
      N=['{}*{}={}'.format(i,n,n*i) for i in range(1,n+1)]
      n+=1
      yield N

大家注意看,用yield来保存N的所有中间状态,代码量小了很多,是不是很简洁
T=table_9_9()
for t in T:
print t
就可以打印九九乘法表了

二.斐波那契数列

1.这是一个非常著名的序列,又称兔子数列,生成这样的序列有很多种方法,有的用循环,有的用递归等很多方法,先看一种简单的方法实现的:

def fab0(max):
   n,a,b=0,0,1
   fab_list=[]
   while n<max:
      fab_list.append(b)
      a,b=b,a+b 
      n+=1

print fab0(5)
>>[1, 1, 2, 3, 5]

2.但是这样做有点麻烦哦
需要有一个列表去存储数据
用return只能返回最后的结果,不能返回序列变化的过程,有没有更简单的方法呢,当然有啦,继续看,该我们的生成器排上用场了

补充一句:就算你用list来保存,但是会多一些代码,没有yield这么简单高效,而且若你要返回这个列表,保存所有的状态,必须要放在函数的底部,如果是想函数中间对一些状态保存,就无法用return了(因为一旦return就出去了)

def fab2(max):
   n,a,b=0,0,1
   fab_list=[]
   for i in range(max):
      fab_list.append(b)
      yield fab_list
      a,b=b,a+b

for n in fab2(7):
   print n

打印输出:
[1]
[1, 1]
[1, 1, 2]
[1, 1, 2, 3]
[1, 1, 2, 3, 5]
[1, 1, 2, 3, 5, 8]
[1, 1, 2, 3, 5, 8, 13]

三.杨辉三角

杨辉三角是一个比较有意思的序列,是我国数学史上的一个伟大成就,下面我们就用生成器去产生这样的序列,很简洁,下面的算法最巧妙在于,构建一个[1,0],[1,1,0]这样的序列,大家可以仔细看一下

def triangle(max):
   N=[1]
   n=0
   while n <max:
      yield N
      N.append(0)
      N=[N[i-1]+N[i] for i in range(len(N))]
      n+=1
for t in triangle(10):
   print t

打印输出:
[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]

好,看完上面三个小例子希望能让大家对生成器理解更深一些,对于生成器还有一些send(),close()和throw()方法,特别是send()不仅可以传值给yield,还能恢复生成器,大大简化协同程序的实现,后面我找到合适的例子,会展开给大家讲.

其实yield用的比较多是在爬虫里面,有用过爬虫的同学一定知道scrapy框架,里面就会有yield,所以小伙伴们一定要把基础学扎实了,这样无论是学爬虫框架,还是学web框架,数据分析都会很容易上手的.

    原文作者:菜鸟学python
    原文地址: https://www.jianshu.com/p/e30ae5d94f2d
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞