生成器迭代器

Posted 寻寻觅觅

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了生成器迭代器相关的知识,希望对你有一定的参考价值。

一、列表生成式

现在有个需求,看列表[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],要求你把列表里的每个值加1

a = [i+1 for i in range(10)]
print(a)

输出:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

这样的写法就叫做列表生成式

二、生成器(generator

要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator:

g = (i+1 for i in range(10))  # 创建了一个generator

相当于generator保存了一种算法,当你需要时才给你生成数据,你不需要,它就停在那里,这与列表相比,比较节省内存空间。
generator只能前进,不能往后退,当生成完了之后就不再生产。

可以通过next()函数获得生成器的下一个值,若生产完了就会报错。

可以用for循环或while循环来迭代generator:

技术分享图片
g = (i+1 for i in range(3))  # 创建了一个generator
for n in g:
    print(n)

输出:
1
2
3
View Code

使用for循环,当生成完之后不会报错。


在python3中,range()就是一个生成器,执行语句:print(range(3)) ,结果是:range(0,3)

在python2中,执行语句:print(range(3)) ,结果是:0,1,2 ,相当于range()是一个列表

在python2中,执行语句:print(xrange(3)) ,结果是:range(0,3),与python3一样,是一个生成器

斐波拉契数列

斐波那契数列指的是这样一个数列 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89,..........

第0项是0,第1项是第一个1。这个数列从第2项开始,每一项都等于前两项之和。

  有如下代码:

技术分享图片
def fib(max):
    n, a, b = 0, 0, 1  # n:循环次数,a:第一个数,b:第二个数
    while n <= max:
        print(b)
        a, b = b, a+b
        n += 1
    return

fib(4)

输出:
1
1
2
3
5
View Code

程序将会输出所有计算结果。
  使用生成器:

技术分享图片
def fib(max):
    n, a, b = 0, 0, 1  # n:循环次数,a:第一个数,b:第二个数
    while n <= max:
        yield b  # 把函数的执行结果冻结在这一步,并且把b的值返回给外面的next(f)
        a, b = b, a+b
        n += 1


f = fib(4)
print(next(f))  # 调用才会生成
print(next(f))

输出:
1
1
View Code

这便是定义generator的另一种方法:如果函数定义中包含了yield关键字,那么这个函数就不再是一个普通的函数,而是一个生成器。
  函数与生成器的区别:

它们的执行流程不同,函数是顺序执行,遇到return或者函数最后一行语句时结束;生成器是在每次调用next()的时候执行,遇到yield语句返回,再次next()调用时,从上次返回的yield语句处继续执行。

return的作用:返回并终止函数

yield的作用:返回并冻结当前的执行过程,(即停留在这一步)

next()的作用:唤醒冻结的执行过程,继续执行,直到遇到下一个yield

send()的作用:唤醒冻结的执行过程,继续执行,并发送一个消息到生成器内部

注意:在生成器中使用return,程序会报错。

技术分享图片
def func(n):
    count = 0
    while count < n:
        print(count)
        count += 1
        sign = yield count
        if sign == "stop":  # 当收到“stop”时停止生产
            print("sign:", sign)
            break
        else:
            print("continue:", sign)


res = func(5)
print(next(res))
res.send("start")
res.send("stop")

输出:
0
1
continue: start
1
sign: stop
View Code

三、迭代器

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

包括以下几种数据类型:

一类是集合数据类型,如listtupledictsetstr等;

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

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

技术分享图片
from collections import Iterable
print(isinstance([], Iterable))  # 判断列表是否是可迭代对象
print(isinstance({}, Iterable))  # 判断字典是否是可迭代对象
print(isinstance("asdfg", Iterable))  # 判断字符串是否是可迭代对象
print(isinstance((x for x in range(10)), Iterable))  # 判断生成器是否是可迭代对象
print(isinstance(100, Iterable))  # 判断数字是否是可迭代对象

输出:
True
True
True
True
False
View Code

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

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

技术分享图片
from collections import Iterator
print(isinstance([], Iterator))  # 判断列表是否是迭代器
print(isinstance({}, Iterator))  # 判断字典是否是迭代器
print(isinstance("asdfg", Iterator))  # 判断字符串是否是迭代器
print(isinstance((x for x in range(10)), Iterator))  # 判断生成器是否是迭代器代对象
print(isinstance(100, Iterator))  # 判断数字是否是迭代器

输出:
False
False
False
True
False
View Code

生成器都是Iterator对象,但listdictstr虽然是Iterable,却不是Iterator

listdictstrIterable变成Iterator可以使用iter()函数:

技术分享图片
from collections import Iterator
print(isinstance(iter([]), Iterator))  # 将列表变为迭代器

输出:
True
View Code

  你可能会问,为什么listdictstr等数据类型不是Iterator

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

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

小结

凡是可作用于for循环的对象都是Iterable类型;

凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;

集合数据类型如listdictstr等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。

Python3的for循环本质上就是通过不断调用next()函数实现的,例如:

技术分享图片
for x in [1, 2, 3, 4, 5]:
    print(x)
View Code

 

实际上完全等价于:

技术分享图片
it = iter([1, 2, 3, 4, 5])  # 获得一个Iterator对象

while True:  # 循环
    try:
        x = next(it)  # 获得下一个值
        print(x)
    except StopIteration:
        break  # 遇到StopIteration就退出循环
View Code

 

 

 

 





以上是关于生成器迭代器的主要内容,如果未能解决你的问题,请参考以下文章

python:可迭代对象,迭代器,生成器函数,生成器的解析举例代码说明

python:可迭代对象,迭代器,生成器函数,生成器的解析举例代码说明

10.迭代器/生成器/协程函数/列表生成器

Interator和Generator

Interator和Generator

Interator和Generator