Python基础之生成器、迭代器

1.列表生成式

  现在有一个列表lis[0,1,2,3,4,5,6,7,8,9],现需要将里面每个元素+1,可以用过遍历、高阶函数map()都能实现,其实还有一个更简单的方法:列表生成式。

  列表遍历

1 lis = [0,1,2,3,4,5,6,7,8,9]
2 b = []
3 for i in lis:
4     b.append(i+1)
5 print(b)
6 结果:
7 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

  高阶函数map()

1 lis = [0,1,2,3,4,5,6,7,8,9]
2 def fun(x):
3     return x +1
4 ret = map(fun,lis)
5 print(list(ret))
6 结果:
7 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

  列表生成式

1 lis = [0,1,2,3,4,5,6,7,8,9]
2 b = [i + 1 for i in lis]
3 print(b)
4 结果:
5 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

  上述方法都是建立在生成一个列表的基础上,当列表的元素贼多时,都加载到内存中会占用很多内存,而上述问题中后面的元素都是可以通过计算推导出来的。于是python中定义了生成器,即一边循环一边计算的机制称之为生成器。

2.生成器

  生成器一次只能生成一个值,消耗的内存大大减少。

  创建生成器有很多种方法,最简单的一种就是将列表生成式中"[]"改成"()"即可。

1 lis = [0,1,2,3,4,5,6,7,8,9]
2 b = (i + 1 for i in lis)
3 print(b)
4 结果:
5 <generator object <genexpr> at 0x000001E69D7DC938>

  列表生成式打印出来的是一个列表,而生成器打印出来的是:<generator object <genexpr> at 0x000001E69D7DC938>。

  若想获取生成器的值,需通过next()获取。

1 lis = [0,1,2,3,4,5,6,7,8,9]
2 b = (i + 1 for i in lis)
3 print(next(b))
4 结果:
5 1

  此时每调用一次next()就会返回一个生成器的值,直到没有更多的元素时,报出StopIteration的错误。

  但是吧,如果一直重复用next()调用太low,可以用for循环来迭代,而且还不怕报StopIteration的错误。

 1 lis = [0,1,2,3,4,5,6,7,8,9]
 2 b = (i + 1 for i in lis)
 3 for i in b:
 4     print(i)
 5 结果:
 6 1
 7 2
 8 3
 9 4
10 5
11 6
12 7
13 8
14 9
15 10
View Code

  生成器是一个特殊的函数,用关键字yield控制,一次只返回一个值,顺序同样从上往下依次执行,但是当遇到yield时返回一个值,且暂停执行,保存当前状态,当遇到另一个__next__()时从此处继续执行。

1 def fun():
2     yield 1
3     yield 2
4     yield 3
5 f = fun()
6 print(f.__next__())
7 结果:
8 1

  也可以用for循环迭代。

 1 def fun():
 2     yield 1
 3     yield 2
 4     yield 3
 5 for i in fun():
 6     print(i)
 7 结果:
 8 1
 9 2
10 3

3.可迭代对象

  可以直接用于for循环的对象统称为可迭代对象。

  集合数据类型:list、tuple、str、set以及生成器都时可迭代对象。

  判断是否时可迭代对象:

1 from collections import Iterable
2 lis = [1,2,3]
3 print(isinstance(lis,Iterable))
4 结果:
5 True

4.迭代器

  可以被next()函数调用,并不断返回下一个值的对象称迭代器。

  迭代器的对象表示的是一个数据流,迭代器可以被next()函数调用返回下一个数据,知道没有数据时,抛出异常错误。

  迭代器时惰性的,可以认为是一个有序序列,但是不知道长度。

  生成器是一种特殊的迭代器。

  list、dict、str是可迭代对象,但不是迭代器

1 from collections import Iterable
2 from collections import Iterator
3 lis = [1,2,3]
4 print(isinstance(lis,Iterable))
5 print(isinstance(lis,Iterator))
6 结果:
7 True
8 False

5.迭代器的基本原理

  上文说过,可以直接用于for循环的对象统称为可迭代对象,实际上一个对象实现了__iter__方法,就可以用for,并且称之为可迭代对象。

1 names = ["a","b","c"]
2 for i in names:
3     print(i)
4 结果:
5 a
6 b
7 c

  当一个实例对象没有__iter__方法时,使用for循环时,解释器会直接现实格式错误,即使用对象名classtest时,报色。

 1 class Classtest(object):
 2 
 3     def __init__(self):
 4         self.names = list()
 5 
 6     def add(self,name):
 7         self.names.append(name)
 8 
 9 
10 classtest = Classtest()
11 classtest.add("a")
12 classtest.add("b")
13 classtest.add("c")
14 
15 for i in classtest:
16     print(i)
View Code

  当加上__iter__时,则只有运行时会报错。

 1 class Classtest(object):
 2 
 3     def __init__(self):
 4         self.names = list()
 5 
 6     def add(self,name):
 7         self.names.append(name)
 8     
 9     def __iter__(self):
10         pass
11 
12 classtest = Classtest()
13 classtest.add("a")
14 classtest.add("b")
15 classtest.add("c")
16 
17 for i in classtest:
18     print(i)
View Code

  事实上,for循环是将__iter__的返回值返回。

 1 class Classtest(object):
 2 
 3     def __init__(self):
 4         self.names = list()
 5         self.count_num = 0
 6 
 7     def add(self,name):
 8         self.names.append(name)
 9 
10     def __iter__(self):
11         return ClassIterator(self)
12 
13 
14 class ClassIterator(object):
15     def __init__(self,obj):
16         self.obj = obj
17 
18     def __iter__(self):
19         pass
20 
21     def __next__(self):
22         return 123
23 
24 
25 classtest = Classtest()
26 classtest.add("a")
27 classtest.add("b")
28 classtest.add("c")
29 
30 for i in classtest:
31     print(i)
32 结果:
33 123
34 123
35 无限循环下去...
View Code

  此时,我们通过类与类之间的调用,可以将需要循环的写入__next__方法中,就可以用for循环遍历出classtext对象中列表names的元素。

 1 class Classtest(object):
 2 
 3     def __init__(self):
 4         self.names = list()
 5         self.count_num = 0
 6 
 7     def add(self,name):
 8         self.names.append(name)
 9 
10     def __iter__(self):
11         return ClassIterator(self)
12 
13 class ClassIterator(object):
14     def __init__(self,obj):
15         self.obj = obj
16         self.count_num = 0
17 
18     def __iter__(self):
19         pass
20 
21     def __next__(self):
22         if self.count_num < len(self.obj.names):
23             ret = self.obj.names[self.count_num]
24             self.count_num += 1
25             return ret
26         else:
27             raise StopIteration
28 
29 
30 classtest = Classtest()
31 classtest.add("a")
32 classtest.add("b")
33 classtest.add("c")
34 
35 for i in classtest:
36     print(i)
37 结果:
38 a
39 b
40 c
View Code

  将两个类改进成一个类。

 1 class Classtest(object):
 2 
 3     def __init__(self):
 4         self.names = list()
 5         self.count_num = 0
 6 
 7     def add(self,name):
 8         self.names.append(name)
 9 
10     def __iter__(self):
11         return  self
12 
13     def __next__(self):
14         if self.count_num < len(self.names):
15             ret = self.names[self.count_num]
16             self.count_num += 1
17             return ret
18         else:
19             raise StopIteration
20 
21 
22 classtest = Classtest()
23 classtest.add("a")
24 classtest.add("b")
25 classtest.add("c")
26 
27 for i in classtest:
28     print(i)
View Code

原文地址:https://www.cnblogs.com/foxshu/p/12039646.html