协程-迭代器

1.迭代器

列表,元组都可以迭代。判断一个数据类型是否可以迭代,通过Iterable(是个类),isinstance(a,A)是判断a是否是A的子类(或者说a是否由A产生)。
我们不要单纯认为列表和元组的转换是单纯的转换,就是用到迭代器。比如列表转元组,因为列表,元组都是迭代器,所以先新定义一个空元组,然后通过next方法,next一个,放到元组一个,一直这样循环。
在这里插入图片描述
对象是不可以迭代的,如果想迭代的话(即可以使用for),就得定义__iter__self()方法

>>> class MyList(object):
...     def __init__(self):
...             self.container = []
...     def add(self, item):
...             self.container.append(item)
...     def __iter__(self):
...             """返回一个迭代器"""
...             # 我们暂时忽略如何构造一个迭代器对象
...             pass
...
>>> mylist = MyList()
>>> from collections import Iterable
>>> isinstance(mylist, Iterable)
True
>>>

for循环每次都会取一个值,接着你再用for循环时,它根据你上一个取得值,取下一个,就好像有一个东西记录你下一步该取谁for item in Iterable 循环的本质就是先通过iter()函数获取可迭代对象Iterable的迭代器,然后对获取到的迭代器不断调用next()方法来获取下一个值并将其赋值给item,当遇到StopIteration的异常后循环结束。
在这里插入图片描述
但是对于对象,如果你写了iter()方法,说明它可以迭代了,但是没有一个东西记录你接下来该取哪一个值。想让一个对象实现for循环,仅仅使用iter()方法还不够,iter()方法里必须返回一个对象的引用,什么样的对象引用呢,这个对象里面除了iter()方法之外,还有一个next()方法创建的对象,这个对象就相当于一个迭代器。

通过上面的分析,我们已经知道,迭代器是用来帮助我们记录每次迭代访问到的位置,当我们对迭代器使用next()函数的时候,迭代器会向我们返回它所记录位置的下一个位置的数据。实际上,在使用next()函数的时候,调用的就是迭代器对象的__next__方法(Python3中是对象的__next__方法,Python2中是对象的next()方法)。所以,我们要想构造一个迭代器,就要实现它的__next__方法。但这还不够,python要求迭代器本身也是可迭代的,所以我们还要为迭代器实现__iter__方法,而__iter__方法要返回一个迭代器,迭代器自身正是一个迭代器,所以迭代器的__iter__方法返回自身即可。

注意;print(“是否是一个迭代器”,isinstance(a,A)),print()内是一个%,言外之意就是我们想得到一个字符串,如果里面是一个","我们得到就是一个元组,逗号左面的是元组的一个数据,逗号右面的是另一个数据。

  1 from collections import Iterable                                           
  2 from collections import Iterator
  3 
  4 class Classmates():
  5     def __init__(self):
  6         self.names=list()
  7 
  8     def add(self,name):
  9         self.names.append(name)
 10 
 11     def __iter__(self):
 12         return  cla()
 13 
 14 
 15 class cla():
 16     def __iter__(self):
 17         pass
 18     def __next__(self):
 19         return 11
 20 
 21 classmate=Classmates()
 22 
 23 classmate.add("张第三")
 24 classmate.add("里斯")
 25 classmate.add("王武")
 26 
 27 print("判断classmate对象是否可迭代",isinstance(classmate,Iterable))
 28 classmate_iterator=iter(classmate)
 29 print("判断classmate_iterator是否是迭代器",isinstance(classmate_iterator,It    erator))
 30 print(next(classmate_iterator))

结果为:

wy@ubuntu:~/day1$ python3 b.py 
判断classmate对象是否可迭代 True
判断classmate_iterator是否是迭代器 True
11

改进
我们每次得到迭代器,然后再打印,不够美好,要是直接创建完对象就可以输出结果就好了

执行for循环的时候,先判断classmate是否可迭代,可迭代后,然后自动调用iter()方法,iter()方法会把classmate传递进去,即iter(classmate),然后iter方法里面返回一个值,我们把这个值写成类名,意味着又要创建一个对象(classmate_iterator),return就返回一个对象的引用,直白的讲,就是得到cla()对象的引用,得到cla()对象的引用后,for每循环一次就会调用一次新建对象的next()方法,next()方法把返回值传给i。

  1 from collections import Iterable                                           
  2 from collections import Iterator
  3 
  4 class Classmates():
  5     def __init__(self):
  6         self.names=list()
  7 
  8     def add(self,name):
  9         self.names.append(name)
 10 
 11     def __iter__(self):
 12         return  cla()
 13 
 14 
 15 class cla():
 16     def __iter__(self):
 17         pass
 18     def __next__(self):
 19         return 11
 20 
 21 classmate=Classmates()
 22 
 23 classmate.add("张第三")
 24 classmate.add("里斯")
 25 classmate.add("王武")
 26 
 27 #print("判断classmate对象是否可迭代",isinstance(classmate,Iterable))
 28 #classmate_iterator=iter(classmate)
 29 #print("判断classmate_iterator是否是迭代器",isinstance(classmate_iterator,I    terator))
 30 #print(next(classmate_iterator))
 31 
 32 for i in classmate:
 33     print(i) 

执行结果会打印很多的11

11
11
11
11
11
11
11
11
11
11
11
11
11
11
11
11
11
^CTraceback (most recent call last):
  File "b.py", line 33, in <module>
    print(i)
KeyboardInterrupt

==我们打印11是迭代器的11,我们要这个结果没有任何用,我们想要的是classmate对象内的数据,for i in classmate这个for循环,每循环一次,调用一次next()方法,所以我们要在next()方法的return返回值做改进即可,想让return的返回值关联到classmate对象的列表,在创建cla对象时,在cla()中写上一个对象的引用,那么接下来存起来,那么next()方法就可以取对象里面引用的东西了。
cla(self)意味着classmate对象的引用给了cla一份,然后用init方法接收。

  1 from collections import Iterable                                           
  2 from collections import Iterator
  3 import time
  4 class Classmates():
  5     def __init__(self):
  6         self.names=list()
  7 
  8     def add(self,name):
  9         self.names.append(name)
 10 
 11     def __iter__(self):
 12         return  cla(self)
 13 
 14 
 15 class cla():
 16     def __init__(self,obj):
 17         self.obj=obj
 18     def __iter__(self):
 19         pass
 20     def __next__(self):
 21         return self.obj.names[0]
 22 
 23 classmate=Classmates()
 24 
 25 classmate.add("张第三")
 26 classmate.add("里斯")
 27 classmate.add("王武")
 28 
 29 #print("判断classmate对象是否可迭代",isinstance(classmate,Iterable))
 30 #classmate_iterator=iter(classmate)
 31 #print("判断classmate_iterator是否是迭代器",isinstance(classmate_iterator,I    terator))
 32 #print(next(classmate_iterator))
 33 
 34 for i in classmate:
 35     print(i)
 36     time.sleep(1)  

这里要解释一下,我们在第12行代码处的cla类中写了self参数,这样cla迭代器就可以引用Classmates的数据了,此时我们还需在cla类中写它的构造方法,这样cla类每一次实例化对象,都会自动调用构造方法,然后构造方法的属性就可以引用Classmates的数据,这里的代码:self.obj=obj,其中等号右边的obj指的是Classmates的实例化对象,self.obj就是cla类的属性,它指向的是Classmates的实例化对象,这个时候原本"箭头"指向的是Classmates的实例化对象,在创建一个对象后,"箭头"指向了新创建的对象,新创建的对象如果想关联到Classmates的实例化对象,就需要在init方法里找到一个属性,这个属性指向原来的对象就可以了,然后现在的程序得到了classmate_iterator对象的引用,得到了这个对象引用之后,接下来每for一次就调用next()方法。
在这里插入图片描述
执行结果(依据的是文章中的代码,而不是图片内的代码):

wy@ubuntu:~/day1$ python3 b.py 
张第三
张第三
张第三
张第三
张第三
张第三
^CTraceback (most recent call last):
  File "b.py", line 36, in <module>
    time.sleep(1)
KeyboardInterrupt

完善
注意self.count的初始化不能写在next方法里,必须写在init方法内,而且return的使用要在self.count加1操作完成后。
raise StopIteration是自动让程序执行完成后结束运行

  1 from collections import Iterable                                           
  2 from collections import Iterator
  3 import time
  4 class Classmates():
  5     def __init__(self):
  6         self.names=list()
  7 
  8     def add(self,name):
  9         self.names.append(name)
 10 
 11     def __iter__(self):
 12         return  cla(self)
 13 
 14 
 15 class cla():
 16     def __init__(self,obj):
 17         self.obj=obj
 18         self.count=0
 19     def __iter__(self):
 20         pass
 21     def __next__(self):
 22         if self.count<len(self.obj.names):
 23             ret=self.obj.names[self.count]
 24             self.count+=1
 25             return ret
 26         else:
 27             raise StopIteration
 28 
 29 classmate=Classmates()
 30 
 31 classmate.add("张第三")
 32 classmate.add("里斯")
 33 classmate.add("王武")
 34 
 35 #print("判断classmate对象是否可迭代",isinstance(classmate,Iterable))
 36 #classmate_iterator=iter(classmate)
 37 #print("判断classmate_iterator是否是迭代器",isinstance(classmate_iterator,I    terator))
 38 #print(next(classmate_iterator))
 39 
 40 for i in classmate:
 41     print(i)
 42     time.sleep(1)  

执行结果:

wy@ubuntu:~/day1$ python3 b.py 
张第三
里斯
王武

扩展
迭代器可以是自己,不需要再创建另一个对象,return self返回自己就行。

  1 from collections import Iterable
  2 from collections import Iterator
  3 import time
  4 class Classmates():
  5     def __init__(self):
  6         self.names=list()
  7         self.count=0                                                       
  8 
  9     def add(self,name):
 10         self.names.append(name)
 11 
 12     def __iter__(self):
 13         return self
 14 
 15 
 16     def __next__(self):
 17         if self.count<len(self.names):
 18             ret=self.names[self.count]
 19             self.count+=1
 20             return ret
 21         else:
 22             raise StopIteration
 23 
 24 classmate=Classmates()
 25 
 26 classmate.add("张第三")
 27 classmate.add("里斯")
 28 classmate.add("王武")
 29 
 30 #print("判断classmate对象是否可迭代",isinstance(classmate,Iterable))
 31 #classmate_iterator=iter(classmate)
 32 #print("判断classmate_iterator是否是迭代器",isinstance(classmate_iterator,I    terator))
 33 #print(next(classmate_iterator))
 34 
 35 for i in classmate:
 36     print(i)
 37     time.sleep(1)  

执行结果;

wy@ubuntu:~/day1$ python3 b.py 
张第三
里斯
王武

迭代器应用斐波那契数列
用常规方法,是把数据先存储起来,如果数据大的话,列表存斐波那契数列就很占用空间

  1 
  2 
  3 def main():
  4     a,b=0,1
  5     fo=list()
  6     num=10
  7     count=0
  8     while True:
  9         if count<num:
 10             fo.append(a)
 11             a,b=b,a+b
 12             count+=1
 13         else:
 14             break
 15     for i in fo:                                                           
 16         print(i)
 17 if __name__=="__main__":
 18     main()             

执行结果;

wy@ubuntu:~/day1$ python3 c.py
0
1
1
2
3
5
8
13
21
34

用迭代器就可以占用很少内存,因为它可以实现什么时候用,就什么时候取。

  1 
  2 
  3 class fonacci():
  4     def __init__(self):
  5         self.a,self.b=0,1
  6         self.count=0
  7         self.num=20                                                        
  8 
  9     def __iter__(self):
 10         return self
 11 
 12     def __next__(self):
 13         if self.count<self.num:
 14             ret=self.a
 15             self.a,self.b=self.b,self.a+self.b
 16             self.count+=1
 17             return ret
 18         else:
 19             raise StopIteration
 20 fo=fonacci()
 21 
 22 for i in fo:
 23     print(i)
 24 

执行结果:

wy@ubuntu:~/day1$ python3 c.py
0
1
1
2
3
5
8
13
21
34
55
89
144
233
377
610
987
1597
2584
4181

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值