Python迭代器协议及for循环工作机制详解


Posted in Python onJuly 14, 2020

一、递归与迭代

二、什么是迭代器协议

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

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

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

三、python中强大的for循环机制

for循环的本质:循环所有对象,全部是使用迭代器协议

解释:

有时会想,for循环的本质就是遵循迭代器协议访问对象,那么for循环的对象肯定都是迭代器了啊,没错,那既然这样,for循环可以遍历(字符串,,列表,字典,集合,文件对象),那这些类型的数据肯定都是可迭代对象啊?但是,为什么定义一个列表l=[1,2,3,4]没有next()方法。

(字符串,列表,元组,字典,集合,文件对象)这些都不是可迭代对象,只不过在for循环中,调用了他们内部的__iter__方法,把他们变成了可迭代对象

然后for循环调用可迭代对象的__next__方法去取值,而且for循环会捕捉stoplteration异常,已终止迭代

l=[1,2,3,4,5]
#下标访问方式
print(l[0])
print(l[7]) #超出访问会报IndexError: list index out of range

#遵循迭代器协议的方式
diedai=l.__iter__()
print(diedai.__next__())
print(diedai.__next__())
print(diedai.__next__())
print(diedai.__next__())
print(diedai.__next__())
print(diedai.__next__()) #超出边界会报StopIteration

#for循环访问方式:
#for循环本质就是遵循迭代器协议的访问方式,先调用diedai.__iter__()方法,或者直接diedai=iter(l),然后依次执行diedai.next(),直到for循环捕捉到StopIteration终止循环
#for循环所有对象的本质都是一样的道理

for i in l:     #diedai=l.__iter__()
  print(l[i])   #i=diedai.next()

#使用while模拟for循环做的事情
diedai_l=l.__iter__()
while True:
  try:
    print(diedai_l.__next__())
  except StopIteration:
    print("迭代完毕,终止循环")
    break

四、生成器初探

什么是生成器?

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

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

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

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

为何使用生成器以及生产器的优点:

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

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)




#yield 3相当于return 控制的是函数的返回值
#x=yield的另外一个特性,接受send传过来的值,赋值给x
# def test():
#   print('开始啦')
#   firt=yield #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)





# 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)
    c2.send('包子 %s' %i)
producer()

生产器小结

1、生成器是可迭代对象

2、实现了延迟计算、省内存

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

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

#1、三元表达式
name="alex"
name="yangyl"
res="1" if name=="yangyl" else "2"
print(res)

egg_list=["鸡蛋%s" %i for i in range(10) ]  #列表解析
print(egg_list)

#使用生产器获取
egg_two=("鸡蛋%s" %i for i in range(10))   #生产器表达式
print(egg_two)
print(egg_two.__next__())
print(next(egg_two))      #next()本质就是调用__next__

总结:

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

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

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

s1=sum(x ** 2 for x in range(4))
print(s1)

而不用多此一举先构造一个列表

s2=sum([x ** 2 for x in range(4)])
print(s2)

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python 自动提交和抓取网页
Jul 13 Python
Python SQLite3数据库操作类分享
Jun 10 Python
python实现定时播放mp3
Mar 29 Python
Python操作串口的方法
Jun 17 Python
python面向对象多线程爬虫爬取搜狐页面的实例代码
May 31 Python
对PyQt5中的菜单栏和工具栏实例详解
Jun 20 Python
python读取Excel表格文件的方法
Sep 02 Python
解决python中0x80072ee2错误的方法
Jul 19 Python
python编写扎金花小程序的实例代码
Feb 23 Python
Django使用channels + websocket打造在线聊天室
May 20 Python
opencv检测动态物体的实现
Jul 21 Python
使用Django框架创建项目
Jun 10 Python
windows10在visual studio2019下配置使用openCV4.3.0
Jul 14 #Python
解决python pandas读取excel中多个不同sheet表格存在的问题
Jul 14 #Python
Python matplotlib读取excel数据并用for循环画多个子图subplot操作
Jul 14 #Python
python3 循环读取excel文件并写入json操作
Jul 14 #Python
Python爬虫实例——scrapy框架爬取拉勾网招聘信息
Jul 14 #Python
Python爬虫爬取新闻资讯案例详解
Jul 14 #Python
Win10下配置tensorflow-gpu的详细教程(无VS2015/2017)
Jul 14 #Python
You might like
php中变量及部分适用方法
2008/03/27 PHP
PHP下通过exec获得计算机的唯一标识[CPU,网卡 MAC地址]
2011/06/09 PHP
关于查看MSSQL 数据库 用户每个表 占用的空间大小
2013/06/21 PHP
php格式化时间戳
2016/12/17 PHP
JavaScript Event学习第六章 事件的访问
2010/02/07 Javascript
网页图片延时加载的js代码
2010/04/22 Javascript
手把手教你自己写一个js表单验证框架的方法
2010/09/14 Javascript
JS设置获取cookies的方法
2014/01/26 Javascript
node.js中的buffer.toString方法使用说明
2014/12/14 Javascript
探究Javascript模板引擎mustache.js使用方法
2016/01/26 Javascript
JS判断元素是否在数组内的实现代码
2016/03/30 Javascript
Bootstrap开发实战之响应式轮播图
2016/06/02 Javascript
微信小程序 window_x64环境搭建
2016/09/30 Javascript
vue.js从安装到搭建过程详解
2017/03/17 Javascript
layui获取多选框中的值方法
2018/08/15 Javascript
Python ORM框架SQLAlchemy学习笔记之数据添加和事务回滚介绍
2014/06/10 Python
[原创]使用豆瓣提供的国内pypi源
2017/07/02 Python
Python实现带参数的用户验证功能装饰器示例
2018/12/14 Python
python 堆和优先队列的使用详解
2019/03/05 Python
python做反被爬保护的方法
2019/07/01 Python
python 读取修改pcap包的例子
2019/07/23 Python
Python 格式化输出_String Formatting_控制小数点位数的实例详解
2020/02/04 Python
django 实现简单的插入视频
2020/04/07 Python
Python如何根据时间序列数据作图
2020/05/12 Python
Django 解决阿里云部署同步数据库报错的问题
2020/05/14 Python
西班牙床垫网上商店:Colchones.es
2018/05/06 全球购物
Viking Direct荷兰:购买办公用品
2019/06/20 全球购物
西雅图的买手店:Totokaelo
2019/10/19 全球购物
戴森香港官方网站:Dyson香港
2021/02/11 全球购物
就业推荐表自我鉴定
2013/10/29 职场文书
历史专业毕业生的自我鉴定
2013/11/15 职场文书
银行职业规划书范文
2013/12/28 职场文书
乡镇干部先进事迹材料
2014/02/03 职场文书
优秀学生党员先进事迹材料
2014/05/29 职场文书
幼儿园教师的自我评价范文
2014/09/17 职场文书
意外伤害赔偿协议书范本
2014/09/28 职场文书