python基础-迭代器和生成器
一、递归和迭代
1、递归:(问路示例)
2、迭代:简单理解为更新换代( 儿子生孙子的故事)
二、迭代器协议
1.迭代器协议是指:对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么就引起一个StopIteration异常,以终止迭代 (只能往后走不能往前退)
2.可迭代对象:实现了迭代器协议的对象(如何实现:对象内部定义一个__iter__()方法)
3.协议是一种约定,可迭代对象实现了迭代器协议,python的内部工具(如for循环,sum,min,max函数等)使用迭代器协议访问对象。
4、for循环的本质就是遵循迭代器协议去访问对象,那么for循环的对象肯定都是迭代器。
5、不可迭代对象:字符串,列表,元组,字典,集合,文件对象。只不过通过for循环,调用了他们内部的__iter__方法,把他们变成了可迭代对象。
特点:
1.生成器是可迭代对象
2.实现了延迟计算,看内存(按需,执行)
3.生成器本质和其他类型一样,都是实现了迭代器协议,只不过生成器是一边计算,一边生成,从而节省内存空间,其余的可迭代对象可没有好处。
三、迭代器
ps1:
1、遵循迭代器协议访问方式
x='hello'
# print(dir(x))
iter_test=x.__iter__() print(iter_test)
print(iter_test.__next__()) #获取第1个值
print(iter_test.__next__()) #获取第2个值
print(iter_test.__next__()) #获取第3个值
print(iter_test.__next__()) #获取第4个值
print(iter_test.__next__()) #获取第5个值
print(iter_test.__next__()) #超出边界,当for循环结束时,捕捉到StopIteration异常,他就会终止迭代
执行结果:
Traceback (most recent call last):
h
File "D:/python/day9/iter和yield.py", line 14, in <module>
e
print(iter_test.__next__()) #超出边界,当for循环结束时,捕捉到StopIteration异常,终止迭代
l
StopIteration
l
o
ps2:
2、for循环访问方式
for循环l本质就是遵循迭代器协议的访问方式,先调用diedai_l=l.__iter__()方法,或者直接diedai_l=iter(l),然后依次执行diedai_l.next(),直到for循环捕捉到StopIteration终止循环。
for循环所有对象的本质都是一样的原理。
用for循环的方式
l=[1,2,3]
for i in l: #把列表变成i_l=l.__iter_() ,再执行他下面的i_l.__next__()
print(i)
执行结果:
1
2
3
ps3:
3、用索引的方式,遍历列表的值
l=[1,2,3] index=0
while index < len(l):
print(l[index])
index += 1
执行结果:
1
2
3
ps4:
用迭代器的方式
l=[1,2,3]
iter_l=l.__iter__() #遵循迭代器协议,生成可迭代对象
print(iter_l.__next__()) #取列表的值
print(iter_l.__next__()) #取列表的值
print(iter_l.__next__()) #取列表的值
执行结果:
1
2
3
ps5:
下标访问方式
l = ['a', 'b', 'c']
print(l[0])
print(l[1])
print(l[2])
#print(l[3]) #起出边界报错:IndexError
执行结果:
a
b
c
ps6:
集合的方式
方法一:
#集合的方式
s={1,2,3}
for i in s:
print(i)
方法二:
s={1,2,3}
iter_s=s.__iter__() #通过iter方法
print(iter_s)
print(iter_s.__next__()) #调用next
print(iter_s.__next__())
print(iter_s.__next__())
print(iter_s.__next__()) #超出边界,当for循环结束时,捕捉到StopIteration异常,终止迭代
执行结果:
<set_iterator object at 0x00BF4198>
Traceback (most recent call last):
1
File "D:/python/day9/iter and yield.py", line 46, in <module>
2
print(iter_s.__next__()) #超出边界,当for循环结束时,捕捉到StopIteration异常,终止迭代
3
StopIteration
ps7:
字典的方式
#字典的方式
dic={'a':1,'b':2}
iter_d=dic.__iter__()
print(iter_d.__next__())
print(iter_d.__next__())
print(iter_d.__next__())
ps8:
文件的方式
1、创建一个test.txt文件,内容如下:
111111
222222
333333
2、执行下面代码
#文件的方式
f=open('test.txt','r+')
#for i in f:
iter_f=f.__iter__() #遵循可迭代原则,转换成迭代器,要的时候拿到内存,可以节约内存空间
print(iter_f)
print(iter_f.__next__(),end='') #第一行
print(iter_f.__next__(),end='') #第二行
print(iter_f.__next__(),end='') #第三行
print(iter_f.__next__(),end='') #执行完了的时候,就捕捉到StopIteration异常,终止迭代
执行结果:
<_io.TextIOWrapper name='test.txt' mode='r+' encoding='cp936'>
Traceback (most recent call last):
111111
File "D:/python/day9/iter and yield.py", line 64, in <module>
222222
print(iter_f.__next__(),end='')
333333StopIteration #执行完了的时候,就捕捉到StopIteration异常,终止迭代
ps9:
用while去模拟for循环做的事情,实现迭代器的过程
l=[1,2,3,4,5]
diedai_l=l.__iter__()
while True:
try:
print(diedai_l.__next__())
except StopIteration:
# print('迭代完毕了,循环终止了')
break #直接break,捕捉到导常,就不会报StopIteration异常
执行结果:
1
2
3
4
5
迭代器总结:
l=['die','erzi','sunzi','chongsunzi'] #把所有结果都放在内存中,比较占用内存 iter_l=l.__iter__() #转成迭代器形式,可以在任意位置传输(也叫可迭代对象)
print(iter_l)
print(iter_l.__next__()) #第一次调用,得到的结果:die
print(iter_l.__next__()) #第二次调用, 得到的结果:erzi
print(iter_l.__next__()) #第三次调用, 得到的结果:sunzi
print(iter_l.__next__()) #第四次调用, 得到的结果:chongsunzi
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 )示例:
def test():
yield 1 #只要有yield就是生成器
yield 2 #他可以yield多次,yield可以保存函数状态
yield 3
g=test()
print('来自函数',g)
print(g.__next__()) #生成器自动实现了迭成器,所以会有__next__()方法。
print(g.__next__()) #运行一次,相当于保存的是上一次内存里状态的结果
print(g.__next__())
执行结果:
来自函数 <generator object(迭代器对象) test at 0x01B0BAE0>
1
2
3
六、补充知识:
三元表达式
#三元表达式演变过程 # name='alex'
# 'SB' if name == 'alex' else '帅哥' #if判断name=alex就,返回SB;如果不等于alex,就返回帅哥。但SB要写在最前面。
七、三元表达式完整写法
if判断name=alex就,返回SB;如果不等于alex,就返回帅哥。但SB要写在最前面。
name='alex'
name='linhaifeng'
res='SB' if name == 'alex' else '帅哥' #三元表达式
print(res)
执行结果:
帅哥
八、生成器表达式和列表解析
ps1:
生成一个列表
egg_list=[]
for i in range(10):
egg_list.append('鸡蛋%s' %i)
print(egg_list)
执行结果:
['鸡蛋0', '鸡蛋1', '鸡蛋2', '鸡蛋3', '鸡蛋4', '鸡蛋5', '鸡蛋6', '鸡蛋7', '鸡蛋8', '鸡蛋9']
ps2:
列表解析方法(生成列表)
l=['鸡蛋%s' %i for i in range(10)]
print(l)
执行结果:
['鸡蛋0', '鸡蛋1', '鸡蛋2', '鸡蛋3', '鸡蛋4', '鸡蛋5', '鸡蛋6', '鸡蛋7', '鸡蛋8', '鸡蛋9']
ps3:
三元表达式方法(生成列表)
#鸡蛋>5
l1=['鸡蛋%s' %i for i in range(10) if i > 5 ]
# l1=['鸡蛋%s' %i for i in range(10) if i > 5 else i] #没有四元表达式
print(l1) #鸡蛋<5
l2=['鸡蛋%s' %i for i in range(10) if i < 5]
print(l2)
执行结果:
#鸡蛋>5结果:
['鸡蛋6', '鸡蛋7', '鸡蛋8', '鸡蛋9'] #鸡蛋<5结果:
['鸡蛋0', '鸡蛋1', '鸡蛋2', '鸡蛋3', '鸡蛋4']
ps4:
生成器表达式(基于迭代器__next__方法进行取值)
laomuji=('鸡蛋%s' %i for i in range(10)) #生成器表达式
print(laomuji) print(laomuji.__next__()) #基于迭代器__next__方法进行取值
print(laomuji.__next__())
print(next(laomuji))
print(next(laomuji))
print(next(laomuji))
print(next(laomuji))
print(next(laomuji))
print(next(laomuji))
print(next(laomuji))
print(next(laomuji))
#print(next(laomuji)) #超出边界,当for循环结束时,捕捉到StopIteration异常,终止迭代
执行结果:
<generator object <genexpr> at 0x010EBAB0>
鸡蛋0
鸡蛋1
鸡蛋2
鸡蛋3
鸡蛋4
鸡蛋5
鸡蛋6
鸡蛋7
鸡蛋8
鸡蛋9
ps5:
其它
l=[1,2,3,34]
#map(func,l) #可迭代对象
print(sum(l)) #求和,使用的是__iter__()方法转换成可迭代对象 #生成100000000
print(sum(list(range(100000000)))) #sum传给生成器生成一个列表
print(sum(i for i in range(10000000000000))) #没有运行结果
执行结果:
40 4999999950000000
ps6:
生成器(生孩子事例)
#!/usr/bin/env python
# -*- coding:utf-8 -*-
#Author: nulige import time
def test():
print('开始生孩子啦.......')
print('开始生孩子啦.......')
print('开始生孩子啦.......')
yield '我' #return
time.sleep(3)
print('开始生儿子啦.......')
yield '儿子' time.sleep(3)
print('开始生孙子啦.......')
yield '孙子' res=test()
print(res)
print(res.__next__())
print(res.__next__())
print(res.__next__())
执行结果:
<generator object test at 0x012EBB40>
开始生孩子啦.......
开始生孩子啦.......
开始生孩子啦.......
我
开始生儿子啦.......
儿子
开始生孙子啦.......
孙子
ps7:
send触发yield返回值原理
#yield 3相当于return 控制的是函数的返回值
#x=yield的另外一个特性,接受send传过来的值,赋值给x def test():
print('开始啦')
firt = yield 1 # return 1,first=None
print('第一次', firt)
yield 2
print('第二次') t = test()
res = t.__next__() # next(t)
print(res)
# t.__next__()
res=t.send(None)
# res = t.send # ('函数停留在first那个位置,我就是给first赋值的')
print(res)
执行结果:
开始啦
1 第一次 None
2
ps8:
吃包子事例
import time
def producer():
ret=[]
for i in range(100):
time.sleep(0.1)
ret.append('包子%s' %i)
return ret def consumer(res):
for index,baozi in enumerate(res):
time.sleep(0.1)
print('第%s个人,吃了%s' %(index,baozi)) res=producer()
consumer(res)
执行结果:
第0个人,吃了包子0
第1个人,吃了包子1
第2个人,吃了包子2
第3个人,吃了包子3
第4个人,吃了包子4
第5个人,吃了包子5
第6个人,吃了包子6
第7个人,吃了包子7
第8个人,吃了包子8
第9个人,吃了包子9
第10个人,吃了包子10
第11个人,吃了包子11
第12个人,吃了包子12
第13个人,吃了包子13
第14个人,吃了包子14
第15个人,吃了包子15
第16个人,吃了包子16
第17个人,吃了包子17
第18个人,吃了包子18
第19个人,吃了包子19
第20个人,吃了包子20
第21个人,吃了包子21
第22个人,吃了包子22
第23个人,吃了包子23
第24个人,吃了包子24
第25个人,吃了包子25
第26个人,吃了包子26
第27个人,吃了包子27
第28个人,吃了包子28
第29个人,吃了包子29
第30个人,吃了包子30
第31个人,吃了包子31
第32个人,吃了包子32
第33个人,吃了包子33
第34个人,吃了包子34
第35个人,吃了包子35
第36个人,吃了包子36
第37个人,吃了包子37
第38个人,吃了包子38
第39个人,吃了包子39
第40个人,吃了包子40
第41个人,吃了包子41
第42个人,吃了包子42
第43个人,吃了包子43
第44个人,吃了包子44
第45个人,吃了包子45
第46个人,吃了包子46
第47个人,吃了包子47
第48个人,吃了包子48
第49个人,吃了包子49
第50个人,吃了包子50
第51个人,吃了包子51
第52个人,吃了包子52
第53个人,吃了包子53
第54个人,吃了包子54
第55个人,吃了包子55
第56个人,吃了包子56
第57个人,吃了包子57
第58个人,吃了包子58
第59个人,吃了包子59
第60个人,吃了包子60
第61个人,吃了包子61
第62个人,吃了包子62
第63个人,吃了包子63
第64个人,吃了包子64
第65个人,吃了包子65
第66个人,吃了包子66
第67个人,吃了包子67
第68个人,吃了包子68
第69个人,吃了包子69
第70个人,吃了包子70
第71个人,吃了包子71
第72个人,吃了包子72
第73个人,吃了包子73
第74个人,吃了包子74
第75个人,吃了包子75
第76个人,吃了包子76
第77个人,吃了包子77
第78个人,吃了包子78
第79个人,吃了包子79
第80个人,吃了包子80
第81个人,吃了包子81
第82个人,吃了包子82
第83个人,吃了包子83
第84个人,吃了包子84
第85个人,吃了包子85
第86个人,吃了包子86
第87个人,吃了包子87
第88个人,吃了包子88
第89个人,吃了包子89
第90个人,吃了包子90
第91个人,吃了包子91
第92个人,吃了包子92
第93个人,吃了包子93
第94个人,吃了包子94
第95个人,吃了包子95
第96个人,吃了包子96
第97个人,吃了包子97
第98个人,吃了包子98
第99个人,吃了包子99
我是[wupeiqi],我准备开始吃包子了
我是[yuanhao_SB],我准备开始吃包子了
wupeiqi 很开心的把【包子 0】吃掉了
yuanhao_SB 很开心的把【包子 0】吃掉了
wupeiqi 很开心的把【包子 1】吃掉了
yuanhao_SB 很开心的把【包子 1】吃掉了
wupeiqi 很开心的把【包子 2】吃掉了
yuanhao_SB 很开心的把【包子 2】吃掉了
wupeiqi 很开心的把【包子 3】吃掉了
yuanhao_SB 很开心的把【包子 3】吃掉了
wupeiqi 很开心的把【包子 4】吃掉了
yuanhao_SB 很开心的把【包子 4】吃掉了
wupeiqi 很开心的把【包子 5】吃掉了
yuanhao_SB 很开心的把【包子 5】吃掉了
wupeiqi 很开心的把【包子 6】吃掉了
yuanhao_SB 很开心的把【包子 6】吃掉了
wupeiqi 很开心的把【包子 7】吃掉了
yuanhao_SB 很开心的把【包子 7】吃掉了
wupeiqi 很开心的把【包子 8】吃掉了
yuanhao_SB 很开心的把【包子 8】吃掉了
wupeiqi 很开心的把【包子 9】吃掉了
yuanhao_SB 很开心的把【包子 9】吃掉了
总结:
1.把列表解析的[]换成()得到的就是生成器表达式
2.列表解析与生成器表达式都是一种便利的编程方式,只不过生成器表达式更节省内存
3.Python不但使用迭代器协议,让for循环变得更加通用。大部分内置函数,也是使用迭代器协议访问对象的。例如, sum函数是Python的内置函数,该函数使用迭代器协议访问对象,而生成器实现了迭代器协议,所以,我们可以直接这样计算一系列值的和。
生产者消费者模型(单线程一边发送,一边执行)
import time
def producer():
ret=[]
for i in range(100):
time.sleep(0.1)
ret.append('包子%s' %i)
return ret def consumer(name):
print('我是[%s],我准备开始吃包子了' %name)
while True:
baozi=yield
time.sleep(1)
print('%s 很开心的把【%s】吃掉了' %(name,baozi)) def producer():
c1=consumer('wupeiqi')
c2=consumer('yuanhao_SB')
c1.__next__()
c2.__next__()
for i in range(10):
time.sleep(1)
c1.send('包子 %s' %i) #发送的值,就是yield的返回值
c2.send('包子 %s' %i)
producer()
执行结果:
我是[wupeiqi],我准备开始吃包子了
我是[yuanhao_SB],我准备开始吃包子了
wupeiqi 很开心的把【包子 0】吃掉了
yuanhao_SB 很开心的把【包子 0】吃掉了
wupeiqi 很开心的把【包子 1】吃掉了
yuanhao_SB 很开心的把【包子 1】吃掉了
wupeiqi 很开心的把【包子 2】吃掉了
yuanhao_SB 很开心的把【包子 2】吃掉了
wupeiqi 很开心的把【包子 3】吃掉了
yuanhao_SB 很开心的把【包子 3】吃掉了
wupeiqi 很开心的把【包子 4】吃掉了
yuanhao_SB 很开心的把【包子 4】吃掉了
wupeiqi 很开心的把【包子 5】吃掉了
yuanhao_SB 很开心的把【包子 5】吃掉了
wupeiqi 很开心的把【包子 6】吃掉了
yuanhao_SB 很开心的把【包子 6】吃掉了
wupeiqi 很开心的把【包子 7】吃掉了
yuanhao_SB 很开心的把【包子 7】吃掉了
wupeiqi 很开心的把【包子 8】吃掉了
yuanhao_SB 很开心的把【包子 8】吃掉了
wupeiqi 很开心的把【包子 9】吃掉了
yuanhao_SB 很开心的把【包子 9】吃掉了 #运行结果省略部分.....
python基础-迭代器和生成器的更多相关文章
- python基础—迭代器、生成器
python基础-迭代器.生成器 1 迭代器定义 迭代的意思是重复做一些事很多次,就像在循环中做的那样. 只要该对象可以实现__iter__方法,就可以进行迭代. 迭代对象调用__iter__方法会返 ...
- python基础----迭代器、生成器、协程函数及应用(面向过程实例)
一.什么是迭代器协议 1.迭代器协议是指:对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么就引起一个StopIteration异常,以终止迭代 (只能往后走不能往前退) 2.可迭代 ...
- python基础--迭代器、生成器
(1)迭代器 可迭代对象和迭代器的解释如下: ''' 什么是对象?Python中一切皆对象,之前我们讲过的一个变量,一个列表,一个字符串,文件句柄,函数名等等都可称作一个对象,其实一个对象就是一个实例 ...
- python基础--迭代器、生成器、内置函数、面向对象编程
迭代器:迭代器对象从集合的第一个元素开始访问,直到所有的元素都被访问完结束.迭代器只能往前不会后退 迭代:更新换代(重复)的过程,每次的迭代都必须基于上一次的结果 迭代器:迭代取值的工具 使用迭代器的 ...
- Python基础—迭代器、生成器(Day13)
一.迭代器 1.可迭代对象:遵循可迭代协议,内部含有__iter__方法的对象就叫做可迭代对象.(str.list.tulpe.dict.set) 查询数据类型的方法 s = 'laonanhai' ...
- python基础——迭代器
python基础——迭代器 我们已经知道,可以直接作用于for循环的数据类型有以下几种: 一类是集合数据类型,如list.tuple.dict.set.str等: 一类是generator,包括生成器 ...
- python之迭代器与生成器
python之迭代器与生成器 可迭代 假如现在有一个列表,有一个int类型的12345.我们循环输出. list=[1,2,3,4,5] for i in list: print(i) for i i ...
- python基础 (迭代器回顾,生成器,推导式)
1.迭代器回顾 可迭代对象:Iterable 可以直接作用于for循环的对象统称为可迭代对象:Iterable.因为可迭代对象里面存在可迭代协议,所以才会被迭代 可迭代对象包括: 列表(list) 元 ...
- 第五篇、Python之迭代器与生成器
1.迭代和递归等概念 循环(loop):指的是在满足条件的情况下,重复执行同一段代码.比如,while语句,for循环. 迭代(iterate):指的是按照某种顺序逐个访问列表中的每一项.比如,for ...
随机推荐
- Civil 3D API二次开发学习指南
Civil 3D构建于AutoCAD 和 Map 3D之上,在学习Civil 3D API二次开发之前,您至少需要了解AutoCAD API的二次开发,你可以参考AutoCAD .NET API二次开 ...
- UITableViewHeaderFooterView的封装
UITableViewHeaderFooterView的封装 特点 1. 封装的 UITableViewHeaderFooterView 能够让用户更好的自定义自己的 headerView; 2. 封 ...
- AndRodi Strudio中的按钮时件
AndRodi Studio中的按钮时件注册一定要写在onCraete中 @Override protected void onCreate(Bundle savedInstanceState) { ...
- IOS 多线程分类以及多线程的相关操作
直接附上援助链接:http://www.cnblogs.com/kenshincui/p/3983982.html 分享内容还关联到了生产者与消费者模式(其实看明白了整片文章,也就理解了生产者与消费者 ...
- 【从零开始学习Hadoop】--2.HDFS分布式文件系统
1. 文件系统从头说2. Hadoop的文件系统3. 如何将文件复制到HDFS3.1 目录和文件结构3.2 FileCopy.java文件的源代码3.3 编译3.4打包3.5 运行3.6 检查结果 1 ...
- 微软源代码管理工具TFS2013安装与使用详细图文教程(Vs2013)
这篇文章联合软件小编主要介绍了微软源代码管理工具TFS2013安装与使用图文教程,本文详细的给出了TFS2013的安装配置过程.使用教程,需要的朋友可以参考下 最近公司新开发一个项目要用微软的TFS2 ...
- 0026 Java学习笔记-面向对象-抽象类、接口
抽象方法与抽象类 抽象方法用abstract修饰,没有方法体部分,连花括号都不能有: 抽象方法和抽象类都用abstract修饰 包含抽象方法的类一定是抽象类:但不包含抽象方法的类也可以是抽象类 不能创 ...
- Linux 下编译升级 Python
一.Centos下升级python3.4.3 1.下载安装 wget http://www.python.org/ftp/python/3.4.3/Python-3.4.3.tgz wget http ...
- OpenSessionInViewFilter配置和作用
Spring为我们解决Hibernate的Session的关闭与开启问题. Hibernate 允许对关联对象.属性进行延迟加载,但是必须保证延迟加载的操作限于同一个 Hibernate Sessio ...
- linux中判断一个命令是否执行成功
每一条基本命令执行后都有一个返回码,该返回码是用$?表示,执行成功的返回码是0,例如:if [ $? -ne 0 ];then 上一命令执行失败时的操作else 上一命令执行成功时的操作fi例如lin ...