码迷,mamicode.com
首页 > 其他好文 > 详细

迭代器和生成器

时间:2019-08-19 16:01:13      阅读:104      评论:0      收藏:0      [点我收藏+]

标签:取数据   传参   打印   send   ima   next   读取列表   bsp   font   

可迭代协议:

   含有双下方法__iter__的对象就是可迭代对象。

迭代器协议:

   同时含有__iter__和__next__方法的对象就是迭代器。

print(dir([])) #列表内置的方法
print(dir([].__iter__())) #__iter__中内置的方法
print(set(dir([].__iter__())) - set(dir([])))#将得到的方法列表转换成集合,相减得到__iter__方法中独有的内置方法
print(dir([]).__iter__()) #一个可迭代对象加上__iter__方法就是迭代器
print(({}).__iter__()) #字典也是如此

 

打印截图:

技术图片

 

例:

i = [1,2,3,4,5,6,7,8,9,10,11,12,13]
ix = i.__iter__()
print(ix.__length_hint__()) #打印这个可迭代对象中的元素个数
print(ix.__setstate__(3)) #指定开始打印位置,参数为下标,返回值为None
print(ix.__next__())#一条一条打印,这里为4
print(ix.__next__())#5
print(ix.__next__())#6
for s in ix: #内存已经读取列表所有元素,但是从7开始,证明读取一个元素之后,该元素会从内存中释放,也就是说,迭代器读取数据的方式是一条一条的读(读完一个释放一个)
    print(s)#7,8,9,10,11,12,13

# print(ix.__next__())#报错 数据已经读取完毕,内存被释放,读不到数据 #打印: 13 None 4 5 6 7 8 9 10 11 12 13

 

 

 结论:

1、__iter__方法中独有三个内置方法,__length_hint__,__next__,__setstate__。分别的作用是,查看元素的个数,一条一条打印,从哪个位置打印
2、含有__iter__方法的对象就是可迭代对象(可迭代协议)
3、同时含有__iter__方法和__next__方法,那么它就是迭代器(迭代器协议)
4、__iter__方法中包含__next__方法,但不是在同一个层级当中,所以只有__iter__方法不是迭代器,仅仅是一个可迭代对象
5、当一个可迭代对象引用了__iter__方法时,那么这个对象就是迭代器
6、迭代器读取数据的方式可以是用__next__一条一条的读,读取一个元素之后,该元素会从内存中释放,也就是说,迭代器读取数据的方式是一条一条的读(读完一个释放一个),当数据读完还要读取时会报错

迭代器的好处:
  
从容器类型中一个一个的取值,会把所有的值都取到。
  节省内存空间,迭代器并不会在内存中再占用一大块内存,而是随着循环每次生成一个;每次next每次给我一个



生成器函数和生成器:
def generator():
    print(a)
    yield 1
    print(b)
    yield 2
    print(c)
    yield 3
    print(d)
    yield 4


print(generator().__next__())#函数调用后返回一个生成器,直接执行生成器:1
print(generator().__next__())#每次调用函数都会返回一个新的生成器:1
print(generator().__next__())#每次调用函数都会返回一个新的生成器:1

g = generator() #函数调用后返回一个生成器,把它赋值给g,生成一个新的生成器g
print(g) 新的生成器的地址
print(g.__next__())#获取生成器g的数据:1
print(g.__next__()):#2
print(g.__next__()):#3


#打印:
a
1
a
1
a
1
<generator object generator at 0x000001D03DBCDB48>
a
1
b
2
c
3
结论:
  含有yield关键字的函数都是生成器函数,且不能和return一起使用,且需要写在函数体内。yield也可以设置返回值,执行yield后并不会结束程序
  生成器是一个迭代器,生成器函数调用后会返回一个生成器,此时并不会执行函数体内的程序。当把这个生成器重新赋值给一个对象时,会形成一个新的生成器,
执行生成器时,才会执行函数体内的程序。每次调用生成器函数都是返回一个新的生成器,所以不创建对象进行接收生成器时,直接打印是无法获取全部的数据。


send方法:
def generator():
    print(a)
    b = yield 1
    print(b,b)
    yield 2
    print(c)
    yield 3
    print(d)
    l = yield 4
    print(l)

g = generator()
# print(g.send(111))#报错,因为此时没有对应的yield能够接收参数
# print(g.send(None))#不报错,传参值设置为空时,程序直接向下执行
print(g.__next__())#此时程序停在yield 1
# print(g.send(None))
# print(g.send()) #报错
print(g.send(这是一条被send传过来的参数))#执行到这里时,传入的字符串被yield 1接收,赋值给b,程序继续向下执行,打印字符串b,调用b,继续向下执行,返回yield的数据2
print(g.__next__())
print(g.__next__())
#print(g.send(111))#报错,传入的参数被yield 4接收,但下方已经没有数据可供读取


#打印:
a
1
b 这是一条被send传过来的参数
2
c
3
d
4

 

结论:
send与next的作用一样,会返回一条数据,且send支持传参:
send不传参会报错,传的参数被上一个yield接收,然后程序继续向下执行,继续返回一条数据。
获取生成器第一条数据不能使用send进行传参,因为没有对应的yield可以接收参数,传参值设置为None时,程序直接向下执行,不报错。
获取生成器最后一条数据之后使用send进行传参同样会报错,传入的参数被yield接收,但数据已经读取完毕,没有多余的数据能够读取,但传入的参数有效。



 
 

 

 
  
 

 

迭代器和生成器

标签:取数据   传参   打印   send   ima   next   读取列表   bsp   font   

原文地址:https://www.cnblogs.com/aizhinong/p/11374011.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!