python基础-迭代器和生成器

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python基础-迭代器和生成器相关的知识,希望对你有一定的参考价值。

一、递归和迭代

1、递归:(问路示例)

递归算法是一种直接或者间接地调用自身算法的过程。在计算机编写程序中,递归算法对解决一大类问题是十分有效的,它往往使算法的描述简洁而且易于理解。

2、迭代:简单理解为更新换代( 儿子生孙子的故事)

 

二、迭代器协议

1.迭代器协议是指:对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么就引起一个StopIteration异常,以终止迭代 (只能往后走不能往前退)

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

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

4、for循环的本质就是遵循迭代器协议去访问对象,那么for循环的对象肯定都是迭代器。

5、不可迭代对象:字符串,列表,元组,字典,集合,文件对象。只不过通过for循环,调用了他们内部的__iter__方法,把他们变成了可迭代对象。

 

特点:

  1. 访问者不需要关心迭代器内部的结构,仅需通过next()方法不断去取下一个内容
  2. 不能随机访问集合中的某个值,只能从头到尾依次访问
  3. 访问时只能往后走,不能往前退
  4. 便于循环比较大的数据集合,节省内存

 

三、迭代器

ps1:  

   1、遵循迭代器协议访问方式

 1 x=hello
 2 # print(dir(x))
 3 iter_test=x.__iter__()
 4 
 5 print(iter_test)
 6 print(iter_test.__next__())  #获取第1个值
 7 print(iter_test.__next__())  #获取第2个值
 8 print(iter_test.__next__())  #获取第3个值
 9 print(iter_test.__next__())  #获取第4个值
10 print(iter_test.__next__())  #获取第5个值
11 print(iter_test.__next__())  #超出边界,当for循环结束时,捕捉到StopIteration异常,他就会终止迭代
执行结果:
1 Traceback (most recent call last):
2 h
3   File "D:/python/day9/iter和yield.py", line 14, in <module>
4 e
5     print(iter_test.__next__())  #超出边界,当for循环结束时,捕捉到StopIteration异常,终止迭代
6 l
7 StopIteration
8 l
9 o

 

ps2:

2、for循环访问方式

for循环l本质就是遵循迭代器协议的访问方式,先调用diedai_l=l.__iter__()方法,或者直接diedai_l=iter(l),然后依次执行diedai_l.next(),直到for循环捕捉到StopIteration终止循环
 

#for循环所有对象的本质都是一样的原理。

1 l=[1,2,3]
2 for i in l:  #把列表变成i_l=l.__iter_() ,再执行他下面的i_l.__next__()
3     print(i)

执行结果:

1 1
2 2
3 3

 

ps3:

3、用索引的方式,遍历列表的值

1 l=[1,2,3]
2 
3 index=0
4 while index < len(l):
5     print(l[index])
6     index += 1

执行结果:

1 1
2 2
3 3

 

ps4:

用迭代器的方式

1 l=[1,2,3]
2 iter_l=l.__iter__()       #遵循迭代器协议,生成可迭代对象
3 print(iter_l.__next__())  #取列表的值
4 print(iter_l.__next__())  #取列表的值
5 print(iter_l.__next__())  #取列表的值

执行结果:

1 1
2 2
3 3

 

ps5:

用for循环的方式

1 l=[1,2,3]
2 for i in l:
3     print(i)

执行结果:

1 1
2 2
3 3

 

ps6:

集合的方式

方法一:

1 #集合的方式
2 s={1,2,3}
3 for i in s:
4     print(i)

方法二:

1 s={1,2,3}
2 iter_s=s.__iter__()    #通过iter方法
3 print(iter_s)
4 print(iter_s.__next__())   #调用next
5 print(iter_s.__next__())
6 print(iter_s.__next__())
7 print(iter_s.__next__())  #超出边界,当for循环结束时,捕捉到StopIteration异常,终止迭代

执行结果:

1 <set_iterator object at 0x00BF4198>
2 Traceback (most recent call last):
3 1
4   File "D:/python/day9/iter and yield.py", line 46, in <module>
5 2
6     print(iter_s.__next__())  #超出边界,当for循环结束时,捕捉到StopIteration异常,终止迭代
7 3
8 StopIteration

 

ps7:

字典的方式

1 #字典的方式
2 dic={a:1,b:2}
3 iter_d=dic.__iter__()
4 print(iter_d.__next__())
5 print(iter_d.__next__())
6 print(iter_d.__next__())

 

ps8:

文件的方式

1、创建一个test.txt文件,内容如下:

1 111111
2 222222
3 333333

2、执行下面代码

1 #文件的方式
2 f=open(test.txt,r+)
3 #for i in f:
4 iter_f=f.__iter__()   #遵循可迭代原则,转换成迭代器,要的时候拿到内存,可以节约内存空间
5 print(iter_f)
6 print(iter_f.__next__(),end=‘‘)  #第一行
7 print(iter_f.__next__(),end=‘‘)  #第二行
8 print(iter_f.__next__(),end=‘‘)  #第三行
9 print(iter_f.__next__(),end=‘‘)  #执行完了的时候,就捕捉到StopIteration异常,终止迭代

执行结果:

1 <_io.TextIOWrapper name=test.txt mode=r+ encoding=cp936>
2 Traceback (most recent call last):
3 111111
4   File "D:/python/day9/iter and yield.py", line 64, in <module>
5 222222
6     print(iter_f.__next__(),end=‘‘)
7 333333StopIteration    #执行完了的时候,就捕捉到StopIteration异常,终止迭代

 

ps9:

用while去模拟for循环做的事情,实现迭代器的过程

1 l=[1,2,3,4,5]
2 diedai_l=l.__iter__()
3 while True:
4     try:
5         print(diedai_l.__next__())
6     except StopIteration:   
7         # print(‘迭代完毕了,循环终止了‘)
8         break   #直接break,捕捉到导常,就不会报StopIteration异常

执行结果:

1 1
2 2
3 3
4 4
5 5

 

迭代器总结

1 l=[die,erzi,sunzi,chongsunzi]   #把所有结果都放在内存中,比较占用内存
2 
3 iter_l=l.__iter__()        #转成迭代器形式,可以在任意位置传输(也叫可迭代对象)
4 print(iter_l)
5 print(iter_l.__next__())    #第一次调用,得到的结果:die
6 print(iter_l.__next__())    #第二次调用, 得到的结果:erzi
7 print(iter_l.__next__())    #第三次调用, 得到的结果:sunzi
8 print(iter_l.__next__())    #第四次调用, 得到的结果:chongsunzi
9 print(iter_l.__next__())    #超出边界,捕捉到StopIteration异常,终止迭代

 

补充:

next内置函数

说明:next内置函数的next()方法,就是在调用l.__iter__(),下的 __next__()方法

1 l=[‘die‘,‘erzi‘,‘sunzi‘,‘chongsunzi‘]
2 iter_l = l.__iter__()
3 print(next(iter_l))        #next()---->iter_l.__next__()
4 print(next(iter_l))
5 print(next(iter_l))
6 print(next(iter_l))

执行结果:

1 die
2 erzi
3 sunzi
4 chongsunzi

 

 


 生成器(详细讲解)

 

一、什么是生成器?

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

 

二、生成器分类及在python中的表现形式?(Python有两种不同的方式提供生成器)

1.生成器函数:常规函数定义,但是,使用yield语句而不是return语句返回结果。yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次重它离开的地方继续执行

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

 

三、使用生成器的优点:

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

 

四、生成器小结:

1.是可迭代对象

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

3.生成器本质和其他的数据类型一样,都是实现了迭代器协议,只不过生成器附加了一个延迟计算省内存的好处,其余的可迭代对象可没有这点好处。

 

五、生成器(yield )示例:

1 def test():
2     yield 1    #只要有yield就是生成器
3     yield 2    #他可以yield多次
4     yield 3
5 g=test()
6 print(来自函数,g)
7 print(g.__next__())   #生成器自动实现了迭成器,所以会有__next__()方法。
8 print(g.__next__())
9 print(g.__next__())

执行结果:

1 来自函数 <generator object(迭代器对象) test at 0x01B0BAE0>
2 1
3 2
4 3

 

六、补充知识:

三元表达式

1 #三元表达式演变过程
2 
3 # name=‘alex‘
4 # ‘SB‘ if name == ‘alex‘ else ‘帅哥‘  #if判断name=alex就,返回SB;如果不等于alex,就返回帅哥。但SB要写在最前面。

 

七、三元表达式完整写法

if判断name=alex就,返回SB;如果不等于alex,就返回帅哥。但SB要写在最前面。

1 name=alex
2 name=linhaifeng
3 res=‘SB‘ if name == ‘alex‘ else ‘帅哥‘  #三元表达式
4 print(res)

执行结果:

1 帅哥

 

 八、生成器表达式和列表解析

ps1:

生成一个列表

1 egg_list=[]
2 for i in range(10):
3     egg_list.append(鸡蛋%s %i)
4 print(egg_list)

执行结果:

1 [鸡蛋0, 鸡蛋1, 鸡蛋2, 鸡蛋3, 鸡蛋4, 鸡蛋5, 鸡蛋6, 鸡蛋7, 鸡蛋8, 鸡蛋9]

 

 ps2:

列表解析方法(生成列表)

1 l=[鸡蛋%s %i for i in range(10)]
2 print(l)

执行结果:

1 [鸡蛋0, 鸡蛋1, 鸡蛋2, 鸡蛋3, 鸡蛋4, 鸡蛋5, 鸡蛋6, 鸡蛋7, 鸡蛋8, 鸡蛋9]

 

ps3:

三元表达式方法(生成列表)

1 #鸡蛋>5
2 l1=[鸡蛋%s %i for i in range(10) if i > 5 ]
3 # l1=[‘鸡蛋%s‘ %i for i in range(10) if i > 5 else i] #没有四元表达式
4 print(l1)
5 
6 #鸡蛋<5
7 l2=[鸡蛋%s %i for i in range(10) if i < 5]
8 print(l2)

执行结果:

1 #鸡蛋>5结果:
2 [鸡蛋6, 鸡蛋7, 鸡蛋8, 鸡蛋9]
3 
4 #鸡蛋<5结果:
5 [鸡蛋0, 鸡蛋1, 鸡蛋2, 鸡蛋3, 鸡蛋4]

 

ps4:

生成器表达式(基于迭代器__next__方法进行取值)

 1 laomuji=(鸡蛋%s %i for i in range(10)) #生成器表达式
 2 print(laomuji)
 3 
 4 print(laomuji.__next__())  #基于迭代器__next__方法进行取值
 5 print(laomuji.__next__())
 6 print(next(laomuji))
 7 print(next(laomuji))
 8 print(next(laomuji))
 9 print(next(laomuji))
10 print(next(laomuji))
11 print(next(laomuji))
12 print(next(laomuji))
13 print(next(laomuji))
14 #print(next(laomuji))   #超出边界,当for循环结束时,捕捉到StopIteration异常,终止迭代

执行结果:

 1 <generator object <genexpr> at 0x010EBAB0>
 2 鸡蛋0
 3 鸡蛋1
 4 鸡蛋2
 5 鸡蛋3
 6 鸡蛋4
 7 鸡蛋5
 8 鸡蛋6
 9 鸡蛋7
10 鸡蛋8
11 鸡蛋9

 

ps5:

其它

1 l=[1,2,3,34]
2 #map(func,l)   #可迭代对象
3 print(sum(l))  #求和,使用的是__iter__()方法转换成可迭代对象
4 
5 #生成100000000
6 print(sum(list(range(100000000))))
7 
8 #sum传给生成器生成一个列表
9 print(sum(i for i in range(10000000000000)))   #没有运行结果

执行结果:

1 40
2 
3 4999999950000000

 

总结:

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

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

3.Python不但使用迭代器协议,让for循环变得更加通用。大部分内置函数,也是使用迭代器协议访问对象的。例如, sum函数是Python的内置函数,该函数使用迭代器协议访问对象,而生成器实现了迭代器协议,所以,我们可以直接这样计算一系列值的和。



以上是关于python基础-迭代器和生成器的主要内容,如果未能解决你的问题,请参考以下文章

Python基础 ( 六 ) —— 迭代器和生成器

python基础-迭代器和生成器

python---基础知识回顾迭代器和生成器

python基础之三大器中迭代器和生成器

Python成长之路第五篇:Python基础之迭代器和生成器

python基础学习迭代器和生成器