一、递归和迭代

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基础-迭代器和生成器的更多相关文章

  1. python基础—迭代器、生成器

    python基础-迭代器.生成器 1 迭代器定义 迭代的意思是重复做一些事很多次,就像在循环中做的那样. 只要该对象可以实现__iter__方法,就可以进行迭代. 迭代对象调用__iter__方法会返 ...

  2. python基础----迭代器、生成器、协程函数及应用(面向过程实例)

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

  3. python基础--迭代器、生成器

    (1)迭代器 可迭代对象和迭代器的解释如下: ''' 什么是对象?Python中一切皆对象,之前我们讲过的一个变量,一个列表,一个字符串,文件句柄,函数名等等都可称作一个对象,其实一个对象就是一个实例 ...

  4. python基础--迭代器、生成器、内置函数、面向对象编程

    迭代器:迭代器对象从集合的第一个元素开始访问,直到所有的元素都被访问完结束.迭代器只能往前不会后退 迭代:更新换代(重复)的过程,每次的迭代都必须基于上一次的结果 迭代器:迭代取值的工具 使用迭代器的 ...

  5. Python基础—迭代器、生成器(Day13)

    一.迭代器 1.可迭代对象:遵循可迭代协议,内部含有__iter__方法的对象就叫做可迭代对象.(str.list.tulpe.dict.set) 查询数据类型的方法 s = 'laonanhai' ...

  6. python基础——迭代器

    python基础——迭代器 我们已经知道,可以直接作用于for循环的数据类型有以下几种: 一类是集合数据类型,如list.tuple.dict.set.str等: 一类是generator,包括生成器 ...

  7. python之迭代器与生成器

    python之迭代器与生成器 可迭代 假如现在有一个列表,有一个int类型的12345.我们循环输出. list=[1,2,3,4,5] for i in list: print(i) for i i ...

  8. python基础 (迭代器回顾,生成器,推导式)

    1.迭代器回顾 可迭代对象:Iterable 可以直接作用于for循环的对象统称为可迭代对象:Iterable.因为可迭代对象里面存在可迭代协议,所以才会被迭代 可迭代对象包括: 列表(list) 元 ...

  9. 第五篇、Python之迭代器与生成器

    1.迭代和递归等概念 循环(loop):指的是在满足条件的情况下,重复执行同一段代码.比如,while语句,for循环. 迭代(iterate):指的是按照某种顺序逐个访问列表中的每一项.比如,for ...

随机推荐

  1. VS2013新建MVC5项目,使用nuget更新项目引用后发生Newtonsoft.Json引用冲突的解决办法

    错误信息如下: 错误    3    类型“Newtonsoft.Json.JsonPropertyAttribute”同时存在于“c:\Program Files (x86)\Microsoft V ...

  2. Android系统的五种数据存储形式(一)

    Android系统有五种数据存储形式,分别是文件存储.SP存储.数据库存储.contentprovider 内容提供者.网络存储.其中,前四个是本地存储.存储的类型包括简单文本.窗口状态存储.音频视频 ...

  3. Google C++单元测试框架GoogleTest---GTest的Sample1和编写单元测试的步骤

    如果你还没有搭建gtest框架,可以参考我之前的博客:http://www.cnblogs.com/jycboy/p/6001153.html.. 1.The first sample: sample ...

  4. Android Studio调试方法学习笔记

    (注:本人所用Android Studio的Keymap已设为Eclipse copy) 1.设置断点 只有设置断点,才好定位要调试什么地方,否则找不到要调试的地方,无法调试.(调试过程中也可以增加断 ...

  5. Android项目实战(二十六):蓝牙连接硬件设备开发规范流程

    前言: 最近接触蓝牙开发,主要是通过蓝牙连接获取传感器硬件设备的数据,并进行处理. 网上学习一番,现整理出一套比较标准的 操作流程代码. 如果大家看得懂,将来只需要改下 硬件设备的MAC码 和 改下对 ...

  6. SQL Server 使用OPENROWSET访问ORACLE遇到的各种坑总结

    在SQL Server中使用OPENROWSET访问ORACLE数据库时,你可能会遇到各种坑,下面一一梳理一下你会遇到的一些坑. 1:数据库没有开启"Ad Hoc Distributed Q ...

  7. 实时事件统计项目:优化flume:用file channel代替mem channel

    背景:利用kafka+flume+morphline+solr做实时统计. solr从12月23号开始一直没有数据.查看日志发现,因为有一个同事加了一条格式错误的埋点数据,导致大量error. 据推断 ...

  8. PostgreSQL-psql

    打开查看元命令实际执行的sql的功能和关闭 yun=> \set ECHO_HIDDEN on yun=> \set ECHO_HIDDEN off psql中输入\?查看命令提示 资讯性 ...

  9. ubuntu kylin 14.04编译openjdk-7u40

    1.ubuntu kylin 14.04安装依赖 sudo apt-get install build-essential gawk m4 libasound2-dev libcups2-dev li ...

  10. Linux可插拔认证模块(PAM)的配置文件、工作原理与流程

    PAM的配置文件: 我们注意到,配置文件也放在了在应用接口层中,他与PAM API配合使用,从而达到了在应用中灵活插入所需鉴别模块的目的.他的作用主要是为应用选定具体的鉴别模块,模块间的组合以及规定模 ...