初步理解Python中的生成器

前言

没有用过的东西,没有深入理解的东西很难说本身会,并且被别人一问必然破绽百出。虽然以前有接触过python协程的概念,可是只是蜻蜓点水,这两天的一次交谈中,别人问到了协程,顿时语塞,死活想不起来曾经看过的东西,以后忽然想到了yield,但为时已晚,只能说概念不清,因此本篇先缕缕python的生成器和yield关键字。html

什么是生成器

  • 生成器是一个特殊的程序,能够被用做控制循环的迭代行为python

  • 生成器相似于返回值为数组的一个函数,这个函数能够接收参数,能够被调用,可是,不一样于通常的函数会一次性返回包含了全部数值的数组,生成器一次只产生一个值,这样消耗的内粗数量大大减小,并且容许调用函数能够很快的开始处理前几个返回值。所以,生成器看起来像一个函数可是表现的却像一个迭代器。数组

python中的生成器

python提供了两种基本的方式。ide

  • 生成器函数:也是用def来定义,利用关键字yield一次返回一个结果,阻塞,从新开始函数

  • 生成器表达式:返回一个对象,这个对象只有在须要的时候才产生结果code

下面详细讲解。协程

生成器函数

为何叫生成器函数?由于他随着时间的推移生成了一个数值队列。通常的函数在执行完毕以后会返回一个值而后退出,可是生成器函数会自动挂起,而后从新拾起继续执行,他会利用yield关键字关起函数,给调用者返回一个值,同时保留了当前的足够多的状态,可使函数继续执行。生成器和迭代协议是密切相关的,可迭代的对象都有一个__next()__成员方法,这个方法要么返回迭代的下一项,要么引发异常结束迭代。
为了支持迭代协议,拥有yield语句的函数被编译为生成器,这类函数被调用时返回一个生成器对象,返回的对象支持迭代接口,即成员方法__next()__继续从中断处执行执行。
看下面的例子:htm

# codesdef create_counter(n):
    print "create counter"
    while True:        yield n        print 'increment n'
        n += 1cnt = create_counter(2)print cntprint next(cnt)print next(cnt)# output<generator object create_counter at 0x0000000001D141B0>create counter2increment n3

分析一下这个例子:对象


  • 在create_counter函数中出现了关键字yield,预示着这个函数每次只产生一个结果值,这个函数返回一个生成器(经过第一行输出能够看出来),用来产生连续的n值blog

  • 在创造生成器实例的时候,只须要像普通函数同样调用就能够,可是这个调用却不会执行这个函数,这个能够经过输出看出来

  • next()函数将生成器对象做为本身的参数,在第一次调用的时候,他执行了create_counter()函数到yield语句,返回产生的值2

  • 咱们重复的调用next()函数,每次他都会从上次被挂起的地方开始执行,直到再次遇到了yield关键字

为了更加深入的理解,咱们再举一个例子。

#codingdef cube(n):
    for i in range(n):        yield i ** 3for i in cube(5):    print i#output0182764

因此从理解函数的角度出发咱们能够将yield类比为return,可是功能确实彻底不一样,在for循环中,会自动遵循迭代规则,每次调用next()函数,因此上面的结果不难理解。

生成器表达式:

生成器表达式来自于迭代和列表解析的组合,关于列表解析的概念和用法能够参见连接,生成器表达式和列表解析相似,可是他使用尖括号而不是方括号括起来的。以下代码:

>>> # 列表解析生成列表>>> [ x ** 3 for x in range(5)]
[0, 1, 8, 27, 64]>>> >>> # 生成器表达式>>> (x ** 3 for x in range(5))<generator object <genexpr> at 0x000000000315F678>>>> # 二者之间转换>>> list(x ** 3 for x in range(5))
[0, 1, 8, 27, 64]

就操做而言,生成器表若是使用大量的next()函数会显得十分不方便,for循环会自动出发next函数,因此能够按下面方式使用:

>>> for n in (x ** 3 for x in range(5)):    print('%s, %s' % (n, n * n))    
0, 01, 18, 6427, 72964, 4096>>>

二者比较

一个迭代既能够被写成生成器函数,也能够被协程生成器表达式,均支持自动和手动迭代。并且这些生成器只支持一个active迭代,也就是说生成器的迭代器就是生成器自己。

总结

想起了初中时候老师常常说的,眼观千遍,不如手动一遍。

不向静中参妙理,纵然颖悟也虚浮 立乎其大  和而不一样 古之成大事者,不唯有超世之才,亦必有坚韧不拔之志

原文地址:https://www.cnblogs.com/cotyb/p/5260032.html

相关文章
相关标签/搜索