Python学习迭代器与生成器(十)

迭代器与生成器

迭代器

1.迭代器协议:对象必须提供一个next方法,执行这个方法要么返回迭代中的下一项,要么就引起一个StopIteration异常,以总结迭代.(迭代是只能往后不能往前)
2.可迭代对象:实现了迭代器协议的对象(实现方式是在对象内部定义一个__iter__()方法)
3.协议是一种约定,可迭代对象实现了对迭代器协议,python的内部工具使用迭代器协议访问对象如(for循环 max() min() sun()函数等)

for循环本质是循环所有对象,全部使用迭代器协议,for循环可以遍历:字符串\列表\元组\字典\集合\文件对象
但是如列表没有next方式 for循环是如何实现的 具体实现方法如下
正常的for循环

l =  [1,2,3,4,5]
for i in l:  #l----> i_l=l.__iter__()   i---->i_l.__next__()
    print(i)

输出结果

1
2
3
4
5

上述的for循环是进行上面的操作,然后捕捉到StopIteration结束当前操作 如下

字典 集合 文件对象是非序列类型

#字典
dic={'a':1,'b':2}
for  item in dic:
    print(item)
#for 循环字典 打印的是key值,
iter_itme=dic.__iter__()
print(iter_itme.__next__()) #这个打印出的 a 字典的key值

输出结果

a
b
a

文件示例

f =open('a.txt','r+',encoding='utf-8')
#for i in f:  #iter_f=f.__iter__()
#    print(i)
iter_f=f.__iter__()
print(iter_f.__next__())
print(iter_f.__next__())
#这样输出的内容中间会有换行 在后面加end=''没有了
print(iter_f.__next__(),end='')
print(iter_f.__next__(),end='')

下面是用while循环模拟for循环中的迭代器协议


l = [1,2,3,4,5]
iter_l=l.__iter__()
while True:
    try:
        print(iter_l.__next__())
    except StopIteration:
        print('迭代结束')
        break

生成器

生成器可以理解为一种数据类型,这种数据类型自动实现了迭代器协议(其他的数据类型需要调用自己内置的__iter__方法,但是生成器可直接.nest,不需要先调用自己内置的__iter__方法),所以生成器也是可迭代对象

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

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

列表生成器

方式一:

#列表解析  缺点是处理大量数据的时候占用内存量大
l =[]
for i in range(10):  
    l.append('鸡蛋%s'%i)
print(l)

输出结果

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

上面也可以写成如下形式

l = ['鸡蛋%s'%i for i in range(10)]
print(l)

写成生成器的方式

laomuji = ('鸡蛋%s'%i for i in range(10))
print(laomuji)
print(laomuji.__next__())

输出结果

<generator object <genexpr> at 0x00000193D2E245E8>
鸡蛋0

如果要一个个打印出来,可以通过next()函数获得generator的下一个返回值:

print(laomuji.__next__())
print(laomuji.__next__())
print(laomuji.__next__())
print(laomuji.__next__())
print(laomuji.__next__())
print(laomuji.__next__())

yield用法

yield 一旦被采用,那么def后面的代码会立马被认作是一个 generator 而不是一个 function,因为生成的是一个 generator

def test():
    print("第一")
    yield 1
    print('第二')
    yield 2

t=test()
res=t.__next__()
print(res)
print(t.send(None))

上面的send(None)和__next__()作用相同 但可以传值

yield相当于return控制函数的返回值,且它也可以接受send传过来的值

def test():
    print('开始了')
    first = yield  #yield 相当月return 后面跟值 没有值默认为None
    
    print('第一次',first)
    yield 2
    print('第二次')

t = test()
res = t.__next__()
print(res)
res = t.send('函数停留在first这个位置,就是给first赋值的')
print(res)

输出结果

开始了
None
第一次 函数停留在first这个位置,就是给first赋值的
2

程序运行到 first = yield时暂停,且记录该位置,等执行res = t.send(‘函数停留在first这个位置,就是给first赋值的’)时,从上次记录的位置及first = yield开始,把send中的值传给yield send---->yield---->first 及first的值就是***(‘函数停留在first这个位置,就是给first赋值的’)***

import time
def consumer(name):
    print('我是[%s],我要开始吃包子了' %name)
    while True:
        baozi=yield
        time.sleep(1)
        print('%s 很开心的吧【%s】吃掉了' %(name,baozi))

def producer():
    c1=consumer('xxxx1')
    c2=consumer('xxxx2')
    c1.__next__()
    c2.__next__()
    for i in range(10):
        time.sleep(1)
        c1.send('包子%s' %i)
        c2.send('包子%s' %i)
producer()

运行producer() 在producer中又运行了consumer(即c1=consumer(‘xxxx1’)和c2=consumer(‘xxxx2’)),consumer中有yield
所以def consumer是一个生成器对象所以需要next()方法(即c1.next()和c2.next()),下面就是循环10次循环10次的值用send传入

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值