生成器和迭代器

Posted feng0919

tags:

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

一,迭代器(iterator)和可迭代对象(iterable)

1.两者的介绍:

    迭代器:对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么就引起一个Stopiteration异常,以终止迭代(只能往前走不能后退)

 

  可迭代对象:实现了迭代器协议的对象(实现:对象内部定义一个_iter_()方法)

 

     注:字符串、列表、元组、字典、集合、文件对象这些都不是可迭代对象,只不过for循环调用了他们内部的_iter_方法,把他们变成了可迭代对象。

例:可迭代对象的使用方法:
a = [1,2,3]
iter_a = a.__iter__()
print(iter_a.__next__())
print(iter_a.__next__())
print(iter_a.__next__())
    注:
    print(next(iter_a)) = print(iter_a.__next__())
    一个调用python提供的内置函数,一个调用数据类型提供的方法

例:用while去模拟for循环:
a = [1,2,3,5]
iter_a = a.__iter__()
while True:
    try:
        print(iter_a.__next__())
    except StopIteration:
        break

2.迭代器和可迭代对象的判断

    可以使用isinstance()判断

>>> from collections import Iterable
>>> isinstance([], Iterable)
True
>>> isinstance({}, Iterable)
True
>>> isinstance(abc, Iterable)
True
>>> isinstance((x for x in range(10)), Iterable)
True
>>> isinstance(100, Iterable)
False



>>> from collections import Iterator
>>> isinstance((x for x in range(10)), Iterator)
True
>>> isinstance([], Iterator)
False
>>> isinstance({}, Iterator)
False
>>> isinstance(abc, Iterator)
False

    笔者自己画的图,他们之间的关系如图所示

                      技术分享图片

小结:

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

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

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

    Python的for循环本质上就是通过不断调用next()函数实现的.

 

二、生成器

1.什么是生成器:
    可以理解为一种数据类型,这种数据类型自动实现了迭代器协议(其他的数据类型需要调用自己内置的__iter__方法),所以生成器就是可迭代对象。
2.生成器分类:
    1):生成器函数:常规函数定义,但是,使用yield语句而不是return语句返回结果。yield语句一次返回一个结果,在每个据俄国中间,挂起函数的状态,以便下次从他离开的地方继续执行.
    2): 生成器表达式:类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构造一个结果列表。

3.生成器特点:
    1).获得返回值yield(类似函数return)
    2).保留函数的运行状态,下一次运行相当于执行__next()__方法
4.生成器函数总结:
    1).语法上和函数类似:生成器函数和常规函数几乎是一样的。它们都是使用def语句进行定义,差别在于,生成器使用yield语句返回一个值,而常规函数使用return语句返回一个值。
    2).自动实现迭代器协议:对于生成器,Python会自动实现迭代器协议,以便应用到迭代背景中(如for循环、sum函数)。由于生成器自动实现了迭代器协议,所以,我们可以调用你它next方法,并且,在没有值可以返回的时候,生成器自动产生StopIteration异常
    3).挂起状态:生成器使用yield语句返回一个值。yield语句挂起该生成器函数的状态,保留足够的信息,以便之后从它离开的地方继续执行

#--------包子案例:商家做包子,客人吃包子
import time
def product_baozi():
     for i in range(100):
         yield 做好了包子%s%i
         time.sleep(3)
baozi = product_baozi()
names = [aaa,bbb,ccc,ddd]
for name in names:
    s = baozi.__next__()
    time.sleep(1)
    print( s[3:],已被%s吃了%name)

5.生成器的send用法

def test():
    print(start)
    num = yield 1
    yield 2,num
    yield 3
a = test()
test0 = a.__next__()
test1 = a.send(24)      #send的作用相当于使生成器继续运行,并且传递的参数为yield的返回值 
test2 = a.__next__()
print(test0)
print(test1)
print(test2)

6.生产者和消费者模型

    通过yield实现在单线程的情况下实现并发运算的效果

import time
def producer(name):
    while True:
        baozi = yield
        time.sleep(1)
        print(%s已制作完毕%baozi)
        print(%s把%s吃了%(name,baozi))
        print(-*30)

def consumption():
    People_eat1 = producer(Jiang)
    People_eat2 = producer(Feng)
    People_eat1.__next__()
    People_eat2.__next__()
    for i in range(10):
        if (i+1)//2 ==1:
            People_eat1.send(包子%s%i)
        else:
            People_eat2.send(包子%s%i)
consumption()










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

Interator和Generator

Interator和Generator

代码详解生成器迭代器

迭代器和生成器

python函数:迭代器和生成器

Python中迭代器和生成器的区别与联系