一、递归和迭代:
1、递归(问路的案例)
递归算法是自己调用自己的过程
2、迭代(父生子,子生孙)
更新换代
二、迭代器协议:
1、迭代器协议:对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么就触发StopTteration异常,已终止迭代(只能往下走,不能往上走)
2、可迭代对象:实现了迭代器协议的对象(如何实现:对象内部定义一个__iter__()方法)
3、协议是一种约定,可迭代对象实现了迭代器协议,Python的内部工具(for循环,sum,max,min函数等)使用迭代器协议访问对象
4、for循环的本质就是遵循迭代器协议取访问对象,那么for循环的对象肯定都是迭代器。
5、不可迭代对象:字符串,列表,元组,字典,集合,文件对象。只不过for循环时,调用了他们的内部__iter__()方法,把他们变成了可迭代对象
-注-
1、生成器是可迭代对象
2、实现了延迟计算,看内存(按需执行)
3、生成器本质和其他类型一样,都是实现了迭代器协议,只不过生成器是一边计算一边生成,从而节省内存空间,其余的可迭代对象没有这个功能
三、迭代器:
1、遵循迭代器协议的访问方式:
1 x='hello' # 非可迭代对象 2 # print(dir(x)) 3 iter_test=x.__iter__() #调用字符串的了iter方法 4 5 print(iter_test) 6 print(iter_test.__next__()) #获取第1个值 ,调用可迭代对象的next方法 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异常,他就会终止迭代
2、for循环的访问方式:
for循环 l 本质是遵循迭代器协议的访问方式,先调用l 的__iter__()方法,使其成为一个可迭代对象,在调用next方法直到for循环捕捉到StopIteration异常
1 # l=[1,2,3] 2 # for i in l: #i_l=l.__iter_() i_l.__next__() 3 # print(i)
3、用索引方式遍历列表的值
1 l=[1,2,3,4] 2 3 index=0 4 while index < len(l): 5 print(l[index]) 6 index += 1
4、用迭代器的方式遍历列表
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__()) #取列表的值
5、迭代的方式遍历集合
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异常,终止迭代
6、迭代的方式遍历字典(默认是key)
dic={'a':1,'b':2}
iter_d=dic.__iter__()
print(iter_d.__next__())
print(iter_d.__next__())
print(iter_d.__next__())
7、迭代的方式访问文件
 1 #文件的方式(创建文件test,txt)
 2 f=open('test.txt','r+')
 3 for i in f:
 4 
 5 =====》》》
 6 
 7 
 8 f=open('test.txt','r+')
 9 iter_f=f.__iter__()   #遵循可迭代原则,转换成迭代器,要的时候拿到内存,可以节约内存空间
10 print(iter_f)
11 print(iter_f.__next__(),end='')  #第一行
12 print(iter_f.__next__(),end='')  #第二行
13 print(iter_f.__next__(),end='')  #第三行
14 print(iter_f.__next__(),end='')  #执行完了的时候,就捕捉到StopIteration异常,终止迭代
8、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 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是python的内置函数
说明:使用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、生成器:
生成器就是迭代器,可以理解为一种数据类型,这种数据类型实现了迭代器协议,其他的数据类型需要调用自己内置的__iter_方法,所以生成器就是可迭代对象。
2、生成器分类以及在Python中的表现形式:(Python有两种不同的方式提供生成器)
①生成器函数:常规函数定义,但是,使用yield 语句代替return语句,但是,yield在同一层函数中,可以多次使用,一次返回一个结果,返回一个结果后,将函数设置为挂起状态,以便下次从他离开的地方继续执行。
②生成器表达式:类似于列表的推导,但是生成器返回按需产生结果的一个对象,而不是一次性构建一个结果列表。
3、生成器示例之 yield
1 def test():
2     yield 1    #只要有yield就是生成器
3     yield 2    #他可以yield多次,yield可以保存函数状态
4     yield 3
5 g=test()
6 print('来自函数',g)
7 print(g.__next__())   #生成器自动实现了迭成器,所以会有__next__()方法。
8 print(g.__next__())   #运行一次,相当于保存的是上一次内存里状态的结果
9 print(g.__next__())
4、补充 知识 之 三元表达式:
1 #三元表达式演变过程 2 3 # name='alex' 4 # 'SB' if name == 'alex' else '帅哥' #if判断name=alex就,返回SB;如果不等于alex,就返回帅哥。但SB要写在最前面。
5、生成器之表达式和列表解析
5.1、for循环生成一个列表
1 1 egg_list=[]
2 2 for i in range(10):
3 3     egg_list.append('鸡蛋%s' %i)
4 4 print(egg_list)
5 
6 ----->
7 
8 1 ['鸡蛋0', '鸡蛋1', '鸡蛋2', '鸡蛋3', '鸡蛋4', '鸡蛋5', '鸡蛋6', '鸡蛋7', '鸡蛋8', '鸡蛋9']
5.2、列表解析生成一个列表
1 l=['鸡蛋%s' %i for i in range(10)] # 也可以是两元 2 print(l)3 ['鸡蛋0', '鸡蛋1', '鸡蛋2', '鸡蛋3', '鸡蛋4', '鸡蛋5', '鸡蛋6', '鸡蛋7', '鸡蛋8', '鸡蛋9']
5.3 三元表达式生成列表
#鸡蛋>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) -------------> 1 #鸡蛋>5结果: 2 ['鸡蛋6', '鸡蛋7', '鸡蛋8', '鸡蛋9'] 3 4 #鸡蛋<5结果: 5 ['鸡蛋0', '鸡蛋1', '鸡蛋2', '鸡蛋3', '鸡蛋4']
5.4、生成器表达式基于迭代器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异常,终止迭代
5.5、其他
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))) #没有运行结果
6、生成器示例之 生孩子:
 1 import time
 2 def test():
 3     print('开始生孩子啦.......')
 4     print('开始生孩子啦.......')
 5     print('开始生孩子啦.......')
 6     yield '我'  #return 
 7     time.sleep(3)
 8     print('开始生儿子啦.......')
 9     yield '儿子'
10 
11     time.sleep(3)
12     print('开始生孙子啦.......')
13     yield '孙子'
14 
15 res=test()
16 print(res)
17 print(res.__next__())   # 打印我 就挂起,后面的不在执行
18 print(res.__next__())
19 print(res.__next__())
7.send触发yield返回值原理
 1 #yield 3相当于return 控制的是函数的返回值
 2 #x=yield的另外一个特性,接受send传过来的值,赋值给x
 3 
 4 def test():
 5     print('开始啦')
 6     firt = yield 1      # return 1,first=None
 7     print('第一次', firt)
 8     yield 2
 9     print('第二次')
10 
11 t = test()
12 res = t.__next__()  # next(t)
13 print(res)
14 # t.__next__()
15 res=t.send(None)
16 # res = t.send  # ('函数停留在first那个位置,我就是给first赋值的')
17 print(res)
8.吃包子
 1 import time
 2 def producer():
 3     ret=[]
 4     for i in range(100):
 5         time.sleep(0.1)
 6         ret.append('包子%s' %i)
 7     return ret
 8 
 9 def consumer(res):
10     for index,baozi in enumerate(res):
11         time.sleep(0.1)
12         print('第%s个人,吃了%s' %(index,baozi))
13 
14 res=producer()
15 consumer(res)
16 
17 
18 
19 ------>
20 
21 
22 
23 
24 第0个人,吃了包子0
25 第1个人,吃了包子1
26 第2个人,吃了包子2
27 第3个人,吃了包子3
28 第4个人,吃了包子4
29 第5个人,吃了包子5
30 ....
总结:
1.把列表解析的[]换成()得到的就是生成器表达式
2.列表解析与生成器表达式都是一种便利的编程方式,只不过生成器表达式更节省内存
3.Python不但使用迭代器协议,让for循环变得更加通用。大部分内置函数,也是使用迭代器协议访问对象的。例如, sum函数是Python的内置函数,该函数使用迭代器协议访问对象,而生成器实现了迭代器协议,所以,我们可以直接这样计算一系列值的和。
补充:send使用 类似next
def foo():
    print('---')
    yield 1
    print('****')
    count = yield 2
    print(count)
a = foo()
s1 = a.send(None) # == a.next() ,第一次send时,如果之前没有执行过next,先传入None
print(s1)
s2 = a.send('aaa') # 先yield 后赋值
print(s2)
来源:https://www.cnblogs.com/JerryZao/p/8634205.html