迭代器

作者: chen_000 | 来源:发表于2017-06-06 19:05 被阅读0次

    一、可迭代对象和迭代器

    1.迭代的概念

    上一次输出的结果为下一次输入的初始值,重复的过程称为迭代,每次重复即一次迭代,并且每次迭代的结果是下一次迭代的初始值

    注:循环不是迭代

    while True: #只满足重复,因而不是迭代

    print('====>')

    2.可迭代的对象

    内置__iter__方法的,都是可迭代的对象。

    list是可迭代对象,dict是可迭代对象,set也是可迭代对象。

    [1,2].__iter__()

    'hello'.__iter__()

    (1,2).__iter__()

    {'a':1,'b':2}.__iter__()

    {1,2,3}.__iter__()

    例如:

    x = [1, 2, 3]

    y = iter(x)

    z = iter(x)

    print(next(y))

    print(next(y))

    print(next(z))

    print(type(x))

    print(type(y))

    输出

    1

    2

    1

    ;

    3.迭代器

    ·1.为什么要有迭代器?

    对于没有索引的数据类型,必须提供一种不依赖索引的迭代方式。

    ·2.迭代器定义:

    迭代器:可迭代对象执行__iter__方法,得到的结果就是迭代器,迭代器对象有__next__方法

    它是一个带状态的对象,他能在你调用next()方法的时候返回容器中的下一个值,任何实现了__iter__和__next__()方法的对象都是迭代器,__iter__返回迭代器自身,__next__返回容器中的下一个值,如果容器中没有更多元素了,则抛出StopIteration异常

    ·3.迭代器的实现

    例:

    i=[1,2,3].__iter__()

    print(i)    #迭代器

    print(i.__next__())

    print(i.__next__())

    print(i.__next__())

    #print(i.__next__()) #抛出异常:StopIteration

    输出

    1

    2

    3

    每次调用next()方法的时候做两件事:

    00001.为下一次调用next()方法修改状态

    00002.为当前这次调用生成返回结果

    迭代器就像一个懒加载的工厂,等到有人需要的时候才给它生成值返回,没调用的时候就处于休眠状态等待下一次调用。

    ·4.如何判断迭代器对象和可迭代对象

    from collections importIterable,Iterator

    'abc'.__iter__()

    ().__iter__()

    [].__iter__()

    {'a':1}.__iter__()

    {1,2}.__iter__()

    f=open('a.txt','w')

    f.__iter__()

    #判断是否为可迭代对象,以下都是

    print(isinstance('abc',Iterable))

    print(isinstance([],Iterable))

    print(isinstance((),Iterable))

    print(isinstance({'a':1},Iterable))

    print(isinstance({1,2},Iterable))

    print(isinstance(f,Iterable))

    #判断是否为迭代器,只有文件是

    print(isinstance('abc',Iterator))

    print(isinstance([],Iterator))

    print(isinstance((),Iterator))

    print(isinstance({'a':1},Iterator))

    print(isinstance({1,2},Iterator))

    print(isinstance(f,Iterator))

    输出

    True

    True

    True

    True

    True

    True

    False

    False

    False

    False

    False

    True

    可迭代对象:只有__iter__方法,执行该方法得到的迭代器对象

    迭代器:有__iter__和__next__()方法

    注:对于迭代器对象来说,执行__iter__方法,得到的结果仍然是它本身

    ·5.迭代器的优点和缺点

    优点:

    1.提供了一种不依赖下标的迭代方式

    2.就跌迭代器本身来说,更节省内存

    缺点:

    1. 无法获取迭代器对象的长度

    2. 不如序列类型取值灵活,是一次性的,只能往后取值,不能往前退

    二、生成器

    1.定义

    生成器(generator)是一个特殊的迭代器,它的实现更简单优雅,yield是生成器实现__next__()方法的关键。它作为生成器执行的暂停恢复点,可以对yield表达式进行赋值,也可以将yield表达式的值返回。

    也就是说,yield是一个语法糖,内部实现支持了迭代器协议,同时yield内部是一个状态机,维护着挂起和继续的状态。

    yield的功能:

    1.相当于为函数封装好__iter__和__next__

    2.return只能返回一次值,函数就终止了,而yield能返回多次值,每次返回都会将函数暂停,下一次next会从上一次暂停的位置继续执行

    例:

    defcounter(n):

    print('start...')

    i=0

    while i < n:

    yield i

    i+=1

    print('end...')

    g=counter(5)

    print(g)

    print(next(g))

    print(next(g))

    print(next(g))

    print(next(g))

    print(next(g))

    # print(next(g))   #会报错

    输出

    start...

    0

    1

    2

    3

    4

    2.生成器函数

    ·生成器函数:常规函数定义,但是,使用yield语句而不是return语句返回结果。yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次重它离开的地方继续执行;

    普通函数return返回

    deflay_eggs(num):

    egg_list=[]

    for egg in range(num):

    egg_list.append('蛋%s' %egg)

    return egg_list

    yikuangdan=lay_eggs(10) #我们拿到的是蛋

    print(yikuangdan)

    输出

    ['蛋0', '蛋1', '蛋2', '蛋3', '蛋4', '蛋5', '蛋6', '蛋7', '蛋8', '蛋9']

    迭代器函数

    deflay_eggs(num):

    for egg in range(num):

    res='蛋%s' %egg

    yield res       #生成器关键语法

    print('下完一个蛋')

    laomuji=lay_eggs(10) #我们拿到的是一只母鸡

    print(laomuji)

    print(laomuji.__next__())       #迭代  蛋0

    print(laomuji.__next__())     #蛋1

    print(laomuji.__next__())       #蛋2

    egg_l=list(laomuji)

    print(egg_l)

    输出

    蛋0

    下完一个蛋

    蛋1

    下完一个蛋

    蛋2

    下完一个蛋

    下完一个蛋

    下完一个蛋

    下完一个蛋

    下完一个蛋

    下完一个蛋

    下完一个蛋

    下完一个蛋

    ['蛋3', '蛋4', '蛋5', '蛋6', '蛋7', '蛋8', '蛋9']

    3.生成器表达式

    ·生成器表达式:类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表;

    ·

    food=yield food_list

    ·

    #g.send('food1'),先把food1传给yield,由yield赋值给food,然后返回给food_list,然后再往下执行,直到再次碰到yield,然后把yield后的返回值返回给food_list

    ·

    注意:开始生成器不能send非空值

    def eater(name):        #协程函数

    print('%s ready to eat' %name)

    food_list=[]

    while True:

    food=yield food_list           #装饰器表达式        food_list.append(food)

    print('%s start to eat %s' %(name,food))

    g=eater('hexin')

    print(g)        #生成器

    print(g.send('food1'))  #传值

    输出

    Traceback (most recent call last):

        #生成器对象

    File "/Users/hexin/PycharmProjects/py3/day5/2.py", line 71, in

    print(g.send('food1'))

    TypeError: can't send non-None value to a just-started generator    #开始生成器不能send非空值

    ·初始化后

    def eater(name):        #协程函数

    print('%s ready to eat' %name)

    food_list=[]

    while True:

    food=yield food_list           #装饰器表达式        food_list.append(food)

    print('%s start to eat %s' %(name,food))

    g=eater('hexin')

    print(g)        #生成器

    next(g) #等同于 g.send(None),初始化

    print(g.send('food1'))

    输出

    hexin ready to eat

    hexin start to eat food1

    ['food1']

    ·为了防止忘记初始化,可利用装饰器进行初始化,如下

    def deco(func):     #初始化函数

    def wrapper(*args,**kwargs):

    res=func(*args,**kwargs)

    next(res)          #等同于 g.send(None),初始化

    return res

    return wrapper

    @deco       #用初始化函数装饰器,调用初始化函数

    def eater(name):        #协程函数

    print('%s ready to eat' %name)

    food_list=[]

    while True:

    food=yield food_list           #装饰器表达式        food_list.append(food)

    print('%s start to eat %s' %(name,food))

    g=eater('hexin')

    # print(g)        #生成器

    # next(g) #等同于 g.send(None),初始化

    print(g.send('food1'))

    print(g.send('food2'))

    print(g.send('food3'))

    输出

    hexin ready to eat

    hexin start to eat food1

    ['food1']

    hexin start to eat food2

    ['food1', 'food2']

    hexin start to eat food3

    ['food1', 'food2', 'food3']

    相关文章

      网友评论

          本文标题:迭代器

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