• 迭代器和生成器


     

    一、递归和迭代

    1、递归:(问路示例)

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

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

    二、迭代器协议

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

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

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

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

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

    特点:

        1.生成器是可迭代对象

        2.实现了延迟计算,看内存(按需,执行)

        3.生成器本质和其他类型一样,都是实现了迭代器协议,只不过生成器是一边计算,一边生成,从而节省内存空间,其余的可迭代对象可没有好处。

    三、迭代器

    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循环所有对象的本质都是一样的原理。

    用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:

    下标访问方式

    1 l = ['a', 'b', 'c']
    2 print(l[0])
    3 print(l[1])
    4 print(l[2])
    5 #print(l[3])  #起出边界报错:IndexError

    执行结果:

    1 a
    2 b
    3 c

    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多次,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

    ps6:

    生成器(生孩子事例)

     1 #!/usr/bin/env python
     2 # -*- coding:utf-8 -*-      
     3 #Author: nulige
     4  
     5 import time
     6 def test():
     7     print('开始生孩子啦.......')
     8     print('开始生孩子啦.......')
     9     print('开始生孩子啦.......')
    10     yield '我'  #return
    11     time.sleep(3)
    12     print('开始生儿子啦.......')
    13     yield '儿子'
    14 
    15     time.sleep(3)
    16     print('开始生孙子啦.......')
    17     yield '孙子'
    18 
    19 res=test()
    20 print(res)
    21 print(res.__next__())
    22 print(res.__next__())
    23 print(res.__next__())

    执行结果:

    1 <generator object test at 0x012EBB40>
    2 开始生孩子啦.......
    3 开始生孩子啦.......
    4 开始生孩子啦.......
    5 我
    6 开始生儿子啦.......
    7 儿子
    8 开始生孙子啦.......
    9 孙子

    ps7:

    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)

    执行结果:

    1 开始啦
    2 1
    3 
    4 第一次 None
    5 2

    ps8:

    吃包子事例

     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)

    总结:

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

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

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

    生产者消费者模型(单线程一边发送,一边执行)

     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(name):
    10     print('我是[%s],我准备开始吃包子了' %name)
    11     while True:
    12         baozi=yield
    13         time.sleep(1)
    14         print('%s 很开心的把【%s】吃掉了' %(name,baozi))
    15 
    16 def producer():
    17     c1=consumer('wupeiqi')
    18     c2=consumer('yuanhao_SB')
    19     c1.__next__()
    20     c2.__next__()
    21     for i in range(10):
    22         time.sleep(1)     
    23         c1.send('包子 %s' %i)  #发送的值,就是yield的返回值
    24         c2.send('包子 %s' %i)
    25 producer()
  • 相关阅读:
    敏捷社区--干货下载 | 10月携程敏捷总动员沙龙
    敏捷开发--洞察敏捷模型,从PO的角度看敏捷产品管理
    携程PMO--小罗说敏捷之WIP限制在制品
    Jmeter分布式压测配置
    Django安装
    Git安装与配置,以及pycharm提交代码到github
    SVN状态图标不显示的解决办法
    PyCharm专业版激活+破解到期时间2100年
    部署python项目到linux服务器
    python+selenium自动化测试,浏览器最大化报错解决方法
  • 原文地址:https://www.cnblogs.com/huangxiaohan/p/7794589.html
Copyright © 2020-2023  润新知