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