小白教程 发表于 2021-4-9 12:52:36

小白教程:Python 生成器 and 迭代器笔记

列表推导假设现在有一个需求,要求我们把列表 中的每个值加 1,那么一般会有以下几种实现方式:方法一(直接使用 for 循环,不推荐):info =
for i, ele in enumerate(info):
    info += 1
print(info)方法二(使用内置的 map 函数):info =
a = map(lambda x:x+1, info)
print(a)方法三(列表推导):info =
a =
print(a)其中,更推荐使用方法三,写法更加的 Pythonic,而且当需要条件过滤时,map 需要借助 filter 函数,使用列表推导的方式更简洁。
生成器通过上述的列表推导可以方便地创建一个列表,但是需要创建的列表很大时,就会占据很大的内存,极端情况下内存甚至无法容纳,而且如果我们仅仅只是需要访问当中某些元素,更是一个极大的浪费,此时,我们就需要考虑用生成器,而不是直接创建并返回列表。
生成器类似于返回值为数组的一个函数,这个函数可以接受参数,可以被调用,但是,不同于一般的函数会一次性返回包括了所有数值的数组,生成器一次只能产生一个值,这样消耗的内存数量将大大减小,而且允许调用函数可以很快的处理前几个返回值,因此生成器看起来像是一个函数,但是表现得却像是迭代器。
要创建一个生成器,有很多种方法,第一种方法就是把列表推导的 [] 换成 (),就创建了一个生成器:>>> L =
>>> L

>>> g = (x * x for x in range(10))
>>> g
<generator object <genexpr> at 0x1022ef630>
生成器中值无法像列表一样直接打印,需要通过 next() 函数获取生成器的下一个返回值:>>> 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 "<stdin>", line 1, in <module>
StopIteration
可以看到,生成器保存的其实是产生元素的算法,每次调用 next(g),就计算出 g 的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出 StopIteration 的错误。因为生成器本身也是可迭代对象,所以一般使用 for 循环:>>> g = (x * x for x in range(10))
>>> for n in g:
...   print(n)
...
0
1
4
9
16
25
36
49
64
81当需要实现的算法比较复杂,列表推导无法很好表达的情况下,则需要通过生成器函数来定义,例如著名的斐波那契数列:def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
      yield b
      a, b = b, a + b
      n = n + 1这就是实现生成器的第二种方式,如果一个函数定义中包含 yield 关键字,那么这个函数就不再是一个普通函数,而是一个生成器。
这里说一下生成器和函数的执行流程,函数是顺序执行的,遇到 return 语句或者最后一行函数语句就返回。而变成生成器的函数,在每次调用 next() 的时候执行,遇到 yield 语句返回,再次被 next() 调用时候从上次的返回 yield 语句处急需执行,也就是用多少,取多少,不占内存。
同样的,既然是生成器,就可以用 for 循环来迭代:>>> for n in fib(6):
...   print(n)
...
1
1
2
3
5
8单总结,Python 提供了两种方法来实现生成器
[*]生成器函数:也是用 def 定义的,利用关键字 yield 一次性返回一个结果,阻塞,重新开始
[*]生成器表达式:返回一个生成器对象,这个对象只有在需要的时候才产生结果

页: [1]
查看完整版本: 小白教程:Python 生成器 and 迭代器笔记