当前位置: 首页 > 文档资料 > Python 学习笔记 >

生成器 generator

优质
小牛编辑
133浏览
2023-12-01

generator 也就是生成器的英文拼写,它的主要作用是生成大批量的数据

  • 方法一 (x for x in ['a', 'v'])

其实也就是把上一章迭代方法中的[]换成了(),那么返回的对象就不同了,前者是生成了一个list后者是生成了一个生成器。

其实跟js中的generator是一样的,打印出来这个生成器的内容只需要使用next()方法就OK了

l = ( x for x in ['1','a','b'])
next(l)
>>> 1
next(l)
>>> a
next(l)
>>> b

直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

generator 函数

如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator:

js中需要将函数名前面添加 例如 function \age(){}

def file():
    while n < 100:
        yield

定义一个generator,依次返回数字1,3,5:


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

调用该generator时,首先要生成一个generator对象,然后用next()函数不断获得下一个返回值:


>>> o = odd()
>>> next(o)
step 1
1
>>> next(o)
step 2
3
>>> next(o)
step 3
5
>>> next(o)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

也就是说它每次使用next方法当做容器并且运行到yield就停止,再次调用next接着上次的继续运行。跟js中是一样的。

定义的函数,其次每次返回的都是generator对象。

我们基本上从来不会用next()来获取下一个返回值,而是直接使用for循环来迭代


def file():
    print('step1')
    yield 1
    print('step2')
    yield 2
    return '应该停止了'
    print('2')
    yield 123


for a in file():
    pass

证明了几点

  • return后面肯定要停止。
  • yield要停止一次
  • for循环可以直接遍历generator无需再使用next
  • 使用for循环无法取得return和yield返回的值

对于最后一个问题,我们可以使用这个办法解决。


while true:
    try:
        x = file()
        print('数据是:',x)
    except StopIteration as e:
        print('数据是:',e.value)
        break

迭代器

我们已经知道,可以直接作用于for循环的数据类型有以下几种:

  • 一类是集合数据类型,如list、tuple、dict、set、str等;

  • 一类是generator,包括生成器和带yield的generator function。

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

可以使用isinstance()判断一个对象是否是Iterable对象:

from collections import Iterable

isinstance([],Iterable)
>>> True

可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。

检查是否是 interator


from collections import interator

isinstance([],interator)
>>> false

这两个就是检查interable迭代器和生成器的差别。

  • interable
  • interator

生成器都是interator对象,但list、dict、str虽然是Iterable,却不是Iterator

将interable变成Interator,使用全局函数iter()即可

a = iter(['1', '2'])

isinstance(a,Interator)

>>> True

你可能会问,为什么list、dict、str等数据类型不是Iterator?

这是因为Python的Iterator对象表示的是一个数据流 ,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。

Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。