生成器

来源:互联网 发布:侯振挺落选院士 知乎 编辑:程序博客网 时间:2024/05/17 09:28

生成器

  • 什么是生成器

    ​ 通过列表生成式,可以直接生成一个列表,但是由于受到内存的限制,列表的容量肯定是有限的。而且在创建一个包含极大元素个数的列表,不仅会占用很大的内存空间,如果我们只需要访问列表中的前几个元素,那么后面很多的元素就占用了很大的空间,白白浪费了空间。如果列表元素可以按照某种算法推算出来,那我们是不是就可以再循环中不断推算出后面的元素呢?这样就不必创建完整的列表,从而节省了大量的内存空间。

    在Python中,这种一边循环一边计算的机制,称之为生成器:generator

  • 创建生成器方法1

    ​ 想要创建一个生成器,第一种方法很简单,只要把一个列表生成式的[ ] 改成( )就行

    In [2]: a = [x for x in range(5)]In [3]: aOut[3]: [0, 1, 2, 3, 4]In [4]: b = (x for x in range(5))In [5]: bOut[5]: <generator object <genexpr> at 0x7f86c8009780>

    ​ 在上面的代码中,a是一个列表,b是一个生成器,那么怎么打印b中的而每个元素呢?

    可以通过next()函数来获取生成器的下一个返回值

    In [6]: next(b)Out[6]: 0In [7]: next(b)Out[7]: 1In [8]: next(b)Out[8]: 2In [9]: next(b)Out[9]: 3In [10]: next(b)Out[10]: 4In [11]: next(b)<hr />StopIteration                             Traceback (most recent call last)<ipython-input-11-641a931447e8> in <module>()----> 1 next(b)StopIteration: 

    生成器中保存的是算法 当我们每次调用next(b)时,就会计算出b的下一个元素的值,直到最后一个元素,没有更多的元素是就会抛出StopIteration异常。我们可以使用for循环来迭代它,也不用关心StopIteration异常的问题。

    In [14]: b = (x for x in range(5))In [15]: for x in b: ....:     print(x) ....:     01234In [16]: 
  • 创建生成器方式2

    ​ generator非常强大。如果推算的算法比较复杂,用类似列表生成式的 for 循环无法实现的时候,还可以用函数来实现。

    ​ 比如,著名的斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到:

    ​ 1, 1, 2, 3, 5, 8, 13, 21, 34, …

    ​ 斐波拉契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易:

    def fib(times):  n = 0  a, b = 0, 1  while n < times:      print(b)      a, b = b, a + b      n += 1fib(6)

    ​ 打印结果:1, 1, 2, 3, 5, 8

    ​ 上面的例子可以看出,函数实际上就是定义了Fibonacci数列的推算规则,可以很据算法推算出后面的值,想要将函数变成生成器,只需要将print(b)改成yield b 就可以了:

    def fib(times):  n = 0  a, b = 0, 1  while n < times:      yield b      a, b = b, a + b      n += 1for x in fib(6):  print(x)

    ​ 打印结果:1, 1, 2, 3, 5, 8

  • yield和send

    ​ 只要函数中有yield,那就不能称之为函数了,应该叫生成器。

    ​ 第一次执行时,从头开始执行,当碰到yield时,会将yield后面的变量的值返回,第二次执行的时候,会从yield之后开始执行。

    ​ 取值时可以用for循环来取值,就不用担心异常的问题。

    ​ send和next相同,都是会从上次停止的地方开始运行。

    ​ 如果首次调用生成器对象,让其产生一个值,一定要用next()或者send(None)
    ​ 取值的时候,只能一个一个的取,不能跳着取值。

  • 总结

    ​ 生成器是这样一个函数,它记住上一次返回时在函数体中的位置。对生成器函数的第二次(或第 n 次)调用跳转至该函数中间,而上次调用的所有局部变量都保持不变。

    生成器不仅“记住”了它数据状态;生成器还“记住”了它在流控制构造(在命令式编程中,这种构造不只是数据值)中的位置。

    ​ 生成器的特点:

    • 节约内存
    • 迭代到下一次的调用时,所使用的参数都是第一次所保留下的,即是说,在整个所有函数调用的参数都是第一次所调用时保留的,而不是新创建的
原创粉丝点击