迭代器 生成器

跟風遠走 提交于 2019-12-27 03:16:28
  • 迭代:迭代是一个重复的过程,每次重复即一次迭代,并且每次迭代的结果是下一次迭代的初始值
1 while True:
2     print('哈') #只是单纯的重复,因此不是迭代
3 
4 lists = [1, 2, 3]
5 count = 0
6 while count < len(lists):
7     print(lists[count])
8     count += 1
迭代的概念
  • 为何要有迭代器:对于序列类型的数据(列表,元组,字符串),我们可以使用索引的方法迭代取出每个元素,但对于非序列类型(集合,字典,文件类型等)这类没有的索引的数据,我们就无法使用上述方法,因此就要使用迭代器
  • 迭代器协议:对象必须提供一个next方法,执行该方法的结束是要么返回迭代中的下一项,要么就引起一个Stoplteration异常以终止迭代(只能前进不能后退)
  • 可迭代对象:内置有__iter__方法的对象,即obj.__iter__()
1 'hello'.__iter__()
2 [1, 2, 3].__iter__()
3 ('a', 'b', 1).__iter__()
4 {'name': 'chen', 'age': 18}.__iter__()
5 {'a', 1}.__iter__()
6 open('test').__iter__()
可迭代对象
  • 迭代器对象:可迭代对象执行obj.__iter__()得到的结果就是迭代器对象,而迭代器对象指的是即内置有__iter__又内置有__next__方法的对
1 # 文件类型是迭代器对象,因为其内部原始就有__next__()和__iter__()方法
2 open('a.txt').__iter__()
3 open('a.txt').__next__()
迭代器对象
  • 协议:一种约定,可迭代对象实现了迭代器协议,python的内部工具(如for max min sum等函数)使用迭代器协议来访问对象
  • 注:迭代器对象一定是可迭代对象,而可迭代对象不一定是迭代器对象

 

for循环机制:

  注:字符串、列表、元组、字典、集合、文件对象,因为其内部有__iter__()方法,故属于可迭代对象,但是本身没有__next__()方法,当用for遍历这些数据类型时,会进行下列操作:

    1.调用这些数据类型中的__iter__()方法,返回值赋值给一个变量,那么这个变量就是迭代器对象

    2.依据迭代器协议,调用__next__()方法,每调用一次就会返回其中的元素,当超出元素个数后,就会报StopIteration错,但是for循环会吞并这个错误,以此来终止循环。

 

1 #基于for循环,我们可以完全不再依赖索引去取值了
2 dic={'a':1,'b':2,'c':3}
3 for k in dic:
4     print(dic[k])
5 
6 #for循环的工作原理
7 #1:执行in后对象的dic.__iter__()方法,得到一个迭代器对象iter_dic
8 #2: 执行next(iter_dic),将得到的值赋值给k,然后执行循环体代码
9 #3: 重复过程2,直到捕捉到异常StopIteration,结束循环
for循环机制

 

用while循环模拟for循环机制:

1 l = [1, 2, 3]
2 iter = l.__iter__()
3 while True:
4     try:
5         print(iter.__next__())
6     except StopIteration:
7         print('循环结束了哟!')
8         break
View Code
  •  迭代器的优缺点

    优点:----提供一种统一性,不依赖于索引的迭代方法

       ----惰性计算,节省内存

    缺点:----无法获取长度(只有在next完毕后才知道到底有多少个值)

       ----一次性的,只能前进不能后退

 

 

  • 生成器:是一种特殊的迭代器,自动实现迭代器协议
  • 生成器优点:1.延迟计算(一次返回一个结果,即不会一次性产生所有结果,对于大量数据来说很有必要)

         2.提高了代码的可读性

  • 创造生成器的方法:

      1.生成器表达式

1 generator = (i for i in range(5)) #生成器
2 print(generator) #<generator object <genexpr> at 0x000000C9B4BC0E08>
3 print(generator.__next__())
4 print(generator.__next__())
5 print(generator.__next__())
6 print(generator.__next__())
7 print(generator.__next__())
8 print(generator.__next__()) #StopIteration
生成器表达式

      2.含有yield的函数:

      1. 语法上与普通函数基本相同,不同点在于用yield代替return来返回值,并且可以有多个yield
      2. 生成器每次调用__next__()方法时,都是从上次迭代结束的位置执行到下个yield的位置,然后将结束的位置作为下次__next__()迭代时的开始位置
 1 def generator():
 2     yield '我'
 3     print('开始生儿子啦!')
 4     yield '儿子'
 5     print('开始生孙子啦!')
 6     yield '孙子'
 7 
 8 generator_obj = generator()
 9 # print(generator_obj) #<generator object generator at 0x000000F704810E08>
10 print('第一次', generator_obj.__next__())  #执行函数内容直到第一个yield后的'我'为止,并停止到这个为止,作为下次next调用的开始
11 #第一次 我
12 print('第二次', generator_obj.__next__())  #从print('开始生儿子啦!')执行到第二个yield后的'儿子'为止,作为下次next调用的开始
13 # 开始生儿子啦!
14 # 第二次 儿子
15 print('第三次', generator_obj.__next__()) #从print('开始生孙子啦!')执行到第三个yield后的'孙子'为为止。
16 # 开始生孙子啦!
17 # 第三次 孙子
生成器函数

 

       生成器函数的优点:可以保留函数的运行状态,运行一次next后就可以进行别的操作,不必等到所有的数据都取出来后才进行操作,相当于“边做边卖”,而不是“都做完了才开始卖”’

 

母鸡下蛋的例子比较几种数据产生的方式:

 

 1 #母鸡下蛋的几种实现方式
 2 
 3 #列表解析的方式
 4 egg_list = ['鸡蛋%s' %i for i in range(1, 5)]
 5 print(egg_list)
 6 #['鸡蛋1', '鸡蛋2', '鸡蛋3', '鸡蛋4']
 7 
 8 #普通函数:全部的蛋都下完了才能进行别的操作
 9 #缺点:1.占用空间大
10       #2.效率低
11 def product_egg():
12     ret = []
13     for i in range(1, 5):
14         ret.append('鸡蛋%s' %i)
15     return ret
16 egg_list = product_egg()
17 print(egg_list)
18 #['鸡蛋1', '鸡蛋2', '鸡蛋3', '鸡蛋4']
19 
20 
21 #生成器函数:边下边进行其他操作
22 #优点:1.尽可能减少内存的占用
23         # 2.效率高
24 def generator_egg():
25     for i in range(1, 5):
26         yield '鸡蛋%s' %i
27 
28 generator = generator_egg()
29 print(generator.__next__()) #鸡蛋1
30 print('休息') #休息
31 print(generator.__next__()) #鸡蛋2
母鸡下蛋

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!