美文网首页
生成器和迭代器

生成器和迭代器

作者: Peng_001 | 来源:发表于2020-05-29 21:22 被阅读0次

参考:https://www.liaoxuefeng.com/wiki/1016959663602400/1017318207388128

生成器

通过列表生成式,我们可以直接创建一个列表。但是,受到内存的限制,列表容量是非常有限的。并且,创建一个巨大容量(比如一百万)的元素的列表,不仅会占用很大的存储空间,而且我们如果只需要访问其中的前面几个元素的话,那后面绝大多数元素占用的空间则全部浪费了。

因此,如果列表元素可以按照某个算法推算出来,我们便可以在循环的过程中不断地推算出后续的元素。这样我们也就不用创建完整的list,从而节省大量的空间。

在python 中,这种边循环边计算的机制,称为generator,生成器。

创建一个生成器

创建生成器的方法有很多种。

1. 通过()创建

我们可以把列表生成式的[] 修改为(),便可以创建一个generator。

>>> g = [g*g for g in range(10) if g%2 == 0]
>>> type(g)
<class 'list'>
>>> a = (g*g for g in range(10) if g%2 == 0)
>>> type(a)
<class 'generator'>

generator 保存的是算法,可以通过next()的方式调出生成器中的元素。

>>> next(a)
0
>>> next(a)
4
>>> next(a)
16
>>> next(a)
36
>>> next(a)
64
>>> next(a)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

但上面这种方式实在太麻烦了。而生成器其实也可以被迭代。所以可以利用for循环。

>>> a = (g*g for g in range(10) if g%2 == 0)
>>> for x in a:
...     x
... 
0
4
16
36
64

2. 通过yield 创建

如果一个函数定义中包含yield关键字,则这个函数就不再是一个普通函数,而是一个生成器。

值得注意的是,生成器和函数的执行流程不太一样,函数是顺序执行,遇到return 或最后一行就返回。可是如果变成了generator 函数,则会在每次调用next()时执行,并且遇到yield 返回。再次执行时从上次返回的yield开始。

普通的函数

def odd():
    print('step 1')
    return 1 # 会直接在此处跳出返回1
    print('step 2')
    return 2
    print('step 3')
    return 3

生成器

def odd():
    print('step 1')
    yield 1
    print('step 2')
    yield 3
    print('step 3')
    yield 5

此时如果调用该生成器

>>> o = odd()
>>> next(o)
step 1
1
>>> next(o)
step 2
3
>>> next(o)
step 3
5

遇到yield 则会中断,继续调用则会继续,直到第四次调用时没有语句执行而报错。

迭代器

我们已经知道,可直接作用于for 的数据类型有几种:
1)集合数据类型,如list, tuple, str, dict等。
2)生成器类型,generator。

这些可以直接作用于for 循环的对象称为可迭代对象:Iterable。

  • 判断可迭代对象
from collections.abc import Iterable
isinstance([], Iterable) # 判断列表是否为可迭代值
  • 判断迭代器
from collections.abc import Iterator
isinstance((x for x in range(10)), Iterator)  # 列表生成式组建迭代器

生成器,generator,都是Iterator, 但list, tuple 等不是,它们是Iterable。

  • 改变Iterable 为Iterator
    可以使用iter()
isinstance(iter([]), Iterator)

迭代器与迭代对象的不同

因为Iterator 本身表示的就只是一个数据流(惰性计算序列),Iterator 可以被next() 调用,并在没有数据时抛出异常StopIteration。我们可以把这个数据流看作为有序数列,但我们却无法提前得知序列的长度,只能不断通过next() 获得下一个数据。

Iterator甚至可以表示无限大的数据流,如全体自然数,而这是list 完全无法做到的。

相关文章

网友评论

      本文标题:生成器和迭代器

      本文链接:https://www.haomeiwen.com/subject/vrglahtx.html