首页 > 代码库 > 迭代器和生成器(一)

迭代器和生成器(一)

一.什么是迭代器协议

1,迭代器协议是指:对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么引起一个Stopiteration异常,

以终止迭代(只能往后走,不能往前退)

2,可迭代对象:实现了迭代器协议的对象(如何实现:对象内部定义一个__iter__()方法)

3,协议是一种约定,可迭代对象实现了迭代器协议,python中的内部工具(例如:for循环,sum,min,max函数等)使用迭代器

协议访问对象

 

二.python中强大的for循环机制

for循环的本质:循环所有对象,全都是使用迭代器协议

(字符串,列表,元组,字典,集合,文件对象)这些都不是可迭代的对象,只不过for在循环式,调用了它们的__iter__方法,

把它们变成了可迭代的对象,然后for循环调用可迭代对象的__next__方法去取值,并且for循环会扑捉到Stopiteration异常,来

终止迭代

 1 list_test = [11,22,33]
 2 list_iter = list_test.__iter__()
 3 print(list_iter.__next__())  #  11
 4 print(list_iter.__next__())  # 22
 5 print(list_iter.__next__())  # 33
 6 print(list_iter.__next__())  # 超出边界就报错StopIteration 
 7 
 8 #for循环list_test本质上就是遵循迭代器的访问方式,
 9 先调用list_iter = list_test.__iter__()方法,或者直接list_iter = iter(list_test)
10 然后依次执行list_iter.next(),直到for循环捕捉到StopIteration终止循环
11 
12 #for循环所有对象的本质都是一样的道理
13 
14 #接下来我们来使用while去模拟一下for循环做的事情
15 list_test = [11,22,33]
16 list_iter = list_test.__iter__()
17 while True:
18     try:
19         print(list_iter.__next__())
20     except StopIteration:
21         print("迭代完成了,循环终止了")
22         break

通过以上上述方式,我们可以看出,for循环就是基于迭代器协议提供了一个统一的可以遍历所有对象的方法,即在遍历之前

先调用对象的__iter__方法将其转换成一个迭代器,然后使用迭代器去实现循环访问,这样所有的对象就都可以通过for循环来

遍历了

三,生成器

生成器可以理解为一种数据类型,这种数据类型自动实现了迭代器协议,(其他的数据类型需要调用自己的内置的__iter__方法,

)所以生成器就是可迭代对象

生成器在python中的形式表现:

1,生成器函数:常规函数定义,但是,使用yield语句而不是return语返回结果,yield语句一次返回一个结果,在每个结果中间,

挂起函数当期的状态,以便下次重它(yield)离开的地方继续执行

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

 

生成器的优点:

python使用生成器对延迟操作提供了支持,所谓延迟操作,是指在需要的时候才产生结果,而不是立即产生结果

生成器小结:

1,是可迭代对象

2,实现了延迟计算,省内存

3,生成器本子和其他数据类型一样,都是实现了迭代器协议,只不过生成器附加了一个延迟计算省内存的好吃,

其余的可迭代对象没有这个功能

 

四:生成器函数

 1 def lay_eggs(num):
 2     egg_list = []
 3     for egg in range(num):
 4         egg_list.append(蛋%s%egg)
 5     return egg_list
 6 
 7 total = lay_eggs(10)
 8 print(total)
 9 
10 #[‘蛋0‘, ‘蛋1‘, ‘蛋2‘, ‘蛋3‘, ‘蛋4‘, ‘蛋5‘, ‘蛋6‘, ‘蛋7‘, ‘蛋8‘, ‘蛋9‘]
11 
12 
13 def lay_eggs(num):
14     for egg in range(num):
15         result = 蛋%s %egg
16         yield  result
17         print(下完一个蛋了)
18 
19 total = lay_eggs(10)  # 我们拿到的是一只老母鸡,可以按照我们的需要进行下蛋
20 print(total)
21 print(total.__next__())
22 print(total.__next__())
23 print(total.__next__())
24 egg_l = list(total)
25 print(egg_l)
26 #演示只能往后不能往前走

 

五:生成器表达式和列表解析

1 #三元表达式
2 #为真的结果 ---表达式---为假的结果
3 
4 name = ying
5 res = very good if name == ying else 不存在
6 print(res)  # very good

列表解析事例

 1 #列表解析
 2 
 3 egg_list = [鸡蛋%s%i for i in range(10)]
 4 print(egg_list)
 5 #[‘鸡蛋0‘, ‘鸡蛋1‘, ‘鸡蛋2‘, ‘鸡蛋3‘, ‘鸡蛋4‘, ‘鸡蛋5‘, ‘鸡蛋6‘, ‘鸡蛋7‘, ‘鸡蛋8‘, ‘鸡蛋9‘]
 6 
 7 
 8 #生成器表达式
 9 egg_list = (鸡蛋%s %i for i in range(10))
10 print(egg_list)
11 print(next(egg_list))  # next本质就是调用__next__
12 print(egg_list.__next__())
13 
14 
15 #<generator object <genexpr> at 0x000000000113C1A8>
16 #鸡蛋0
17 #鸡蛋1

小结:

1,把列表解析的[]换成()得到的就是生成器表达式

2,列表解析与生成器表达式都是一种编程方式,只不过生成器表达式更节省内存空间

3,python不但使用迭代器协议,让for循环变得更加通用,大部分内置函数,也是使用迭代器协议访问对象的

比如,sum函数是python的内置函数,该函数使用迭代器协议访问对象,而生成器实现了迭代器协议,所以

我们可以直接这样来计算一系列值的和

1 print(sum(i for i in range(10)))  # 所有数相加的和
2 print(sum(i** 2 for i in  range(10))) # i的2次方,285

而不用多此一举的先构建一个列表然后在来计算:

1 sum([i** 2 for i in  range(10)])

 

迭代器和生成器(一)