python 生成器

来源:互联网 发布:java连接池原理 编辑:程序博客网 时间:2024/05/20 19:47

1.生成器

生成器的概念要比迭代器稍显复杂,因为生成器是能够返回一个迭代器的函数,其最大的作用是将输入对象返回为一个迭代器。Python中使用了迭代的概念,是因为当需要循环遍历一个较大的对象时,传统的内存载入方式会消耗大量的内存,不如需要时读取一个元素的方式更为经济快捷。

生成器是一次生成一个值的特殊类型函数(特殊的迭代器)。可以将其视为可恢复函数。调用该函数将返回一个可用于生成连续 x 值的生成器Generator。

有两点要先明确:

任意生成器都是迭代器(反之,不成立)
任意生成器,都是一个可以延迟创建值的工厂(可控性)
生成器的创建

将列表生成式中[]改成()
通过列表生成式,可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含百万元素的列表,不仅是占用很大的内存空间,如:我们只需要访问前面的几个元素,后面大部分元素所占的空间都是浪费的。

因此,没有必要创建完整的列表(节省大量内存空间)。在Python中,我们可以采用生成器:边循环,边计算的机制—>generator

>>> L = [x*x for x in range(10)]>>> L[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]>>> g = (x*x for x in range(10))>>> g<generator object <genexpr> at 0x0000028F8B774200>

我们该怎么打印元素呢?

刚刚提到生成器是特殊的迭代器,可以通过next()内置函数来获得generator的下一个返回值:

>>> g = (x*x for x in range(10))>>> g<generator object <genexpr> at 0x0000028F8B774200>>>> next(g)0>>> next(g)1>>> next(g)4>>> next(g)9>>> next(g)16>>> next(g)25>>> next(g)36>>> next(g)49>>> next(g)64>>> next(g)81>>> next(g)Traceback (most recent call last):  File "<input>", line 1, in <module>StopIteration

generator是保存的算法,每次调用next()内置函数,才能计算出下一个元素,但一直这样,是不是有种崩溃的赶脚!这里写图片描述

那种变态的方式肯定不能用的,正因为generator也是可迭代对象,我们可以使用for循环。

>>> g = (x*x for x in range(10))>>> for i in g:...     print(i)...     0149162536496481

这里使用for循环,没有出现异常情况,是和迭代器一样的,都是因为for循环的内部机制。

2.函数—关键字yield创建生成器

简单的说就是在函数的执行过程中,yield语句会把你需要的值返回给调用生成器的地方,然后退出函数,下一次调用生成器函数的时候又从上次中断的地方开始执行,而生成器内的所有变量参数都会被保存下来供下一次使用。

著名的斐波那契数列用列表生成式写不出来,但用函数很简单:

>>> def fib(max):    n, a, b = 0, 0, 1    while n < max:        print(b)        a, b = b, a + b        n = n + 1    return 'done'>>> fib(6)112358'done'

斐波那契数列的推算规则非常类似generator,也就是说上面的函数和generator无限接近了,只需要把print(b)改成yield b就行:

>>> def fib(max):    n, a, b = 0, 0, 1    while n < max:        yield b        a, b = b, a + b        n = n + 1    return 'done'>>> f = fib(6)>>> f<generator object fib at 0x0000022C041D4360>

懵逼这里写图片描述状态:函数和generator执行流程不一样。函数时顺序执行,遇到return语句或者最后一行函数语句就结束,而generator在每次执行next()时,遇到yield语句返回,再次执行时会从上次返回的yield语句处继续执行。

举个简单的生成器例子:

>>> def odd():    print('step 1')    yield 1    print('step 2')    yield(3)    print('step 3')    yield(5)>>> o = odd()>>> next(o)step 11>>> next(o)step 23>>> next(o)step 35>>> next(o)Traceback (most recent call last):  File "<input>", line 1, in <module>StopIteration

小结:

生成器对象就是一种特殊的迭代器,满足迭代器协议,可以调用next()内置函数;对生成器for 循环时,调用iter()方法返回了生成器对象,然后再不断next()迭代,而iter()和next()都是在yield内部实现的。
生成器创建方式:常见两种(列表生成式、函数关键字)

0 0