迭代器与生成器

  • 迭代器
    • 可迭代对象
    • 迭代器对象
    • for循环原理
    • 迭代器的优缺点
  • 生成器
    • yield表达式应用
    • 列表生成式
    • 生成器表达式

迭代器

  迭代器是用来迭代取值的工具 ,迭代是重复反馈过程的活动,每一次对过程的重复称为一次 “迭代”,而每一次迭代得到的结果会作为下一次迭代的初始值,单纯的重复并不是迭代:

while True:msg = input('>>: ').strip()print(msg)

  下面的while循环才是一个迭代过程,不仅满足重复,而且以每次重新赋值后的index值作为下一次循环中新的索引进行取值,反复迭代,最终可以取尽列表中的值:

goods=['mac','lenovo','acer','dell','sony']index=0
while index < len(goods):print(goods[index])index+=1

可迭代对象

  通过索引的方式进行迭代取值仅适用于序列类型(如:字符串、列表、元组),对于非序列类型(如:字典、集合)则必须找到一种不依赖索引来进行迭代取值的方式,这就用到了迭代器。

  在了解迭代器之前必须先弄清楚一个很重要的概念:可迭代对象(Iterable)。从语法形式上讲, 内置有__iter__方法的对象都是可迭代对象 ,字符串、列表、元组、字典、集合、打开的文件都是可迭代对象。

迭代器对象

  调用对象的 __iter__()方法 返回的结果就是一个迭代器对象(Iterator)。 迭代器对象是内置有__iter__和__next__方法的对象

  • __iter__方法:执行迭代器对象的__iter__()方法得到的仍然是迭代器本身
  • __next__方法:执行迭代器对象的__next__()方法就会计算出迭代器中的下一个值

  迭代器是Python提供的一种统一的、不依赖于索引的迭代取值方式,只要目标对象存在多个值,无论它是序列类型还是非序列类型都可以按照迭代器的方式取值:

s={1,2,3} # 可迭代对象s
i=iter(s)  # 本质就是在调用s.__iter__(),返回s的迭代器对象i
print(next(i)) # 本质就是在调用i.__next__()  1
print(next(i)) # 2
print(next(i)) # 3
print(next(i))  #抛出StopIteration的异常,代表无值可取,迭代结束

注意:打开的文件本身就是一个迭代器对象

  有了迭代器之后,我们便可以不依赖索引迭代取值了,使用while循环的实现方式如下:

goods=['mac','lenovo','acer','dell','sony']
i=iter(goods) #每次都需要重新获取一个迭代器对象
while True:try:print(next(i))except StopIteration: #捕捉异常终止循环break

for循环原理

  for循环又称为迭代循环,in后可以跟任意可迭代对象:

goods=['mac','lenovo','acer','dell','sony']
for item in goods:   print(item)

  for循环的工作原理如下:

  • 步骤1:首先会调用可迭代对象goods的内置的__iter__方法拿到一个迭代器对象
  • 步骤2:然后再调用该迭代器对象的__next__方法将取到的值赋给item,执行循环体完成一次循环
  • 重复步骤2,直到捕捉StopIteration异常,结束迭代

迭代器的优缺点

  基于索引的迭代取值,所有迭代的状态都保存在了索引中;而基于迭代器实现迭代的方式不再需要索引,所有迭代的状态就保存在迭代器中。这种处理方式优点与缺点如下:

  • 优点:

    • 为序列和非序列类型提供了一种统一的迭代取值方式
    • 惰性计算:迭代器对象表示的是一个数据流,可以只在需要时才去调用next来计算出一个值。就迭代器本身来说,同一时刻在内存中只有一个值,因而可以存放无限大的数据流。对于其它容器类型(如列表),需要把所有的元素都存放于内存中,受内存大小的限制,可以存放的值的个数是有限的
  • 缺点:
    • 除非取尽,否则无法获取迭代器的长度
    • 只能取下一个值,不能回到开始:迭代器产生后的唯一目标就是重复执行next方法直到值取尽,否则就会停留在某个位置,等待下一次调用next;若是要再次迭代同个对象,你只能重新调用iter方法去创建一个新的迭代器对象,如果有两个或者多个循环使用同一个迭代器,必然只会有一个循环能取到值

生成器

  如果函数体里面包含 yield关键字 ,那么调用函数的时候就不会执行函数体的代码,它的返回值就是一个生成器对象:

def my_range(start,stop,step=1):print('start...')while start < stop:yield startstart+=stepprint('end...')... g=my_range(0,3)
print(g) # <generator object my_range at 0x104105678># 生成器内置有__iter__和__next__方法,所以生成器本身就是一个迭代器print(g.__iter__) # <method-wrapper '__iter__' of generator object at 0x1037d2af0
print(g.__next__) # <method-wrapper '__next__' of generator object at 0x1037d2af0>

  因而我们可以用next触发生成器所对应函数的执行:

next(g) # 触发函数执行直到遇到yield则停止,将yield后的值返回,并在当前位置挂起函数start...0
next(g) # 再次调用next(g),函数从上次暂停的位置继续执行,直到重新遇到yield...1
next(g) # 周而复始...2
next(g) # 触发函数执行没有遇到yield则无值返回,即取值完毕抛出异常结束迭代end...Traceback (most recent call last):File "<stdin>", line 1, in <module>StopIteration

  既然生成器对象属于迭代器,那么就可以使用for循环迭代:

def countdown(num):print("countdown start...")while num > 0:yield numnum -= 1print("countdown end...")for i in countdown(3):print(i)# countdown start...
# 3
# 2
# 1
# countdown end...

  通过yield关键字就有可以实现自定义迭代器。yield可以用于返回值,但它和return不同,函数一旦遇到return就结束了,而yield可以保存函数的运行状态挂起函数,用来返回多次值。

yield表达式应用

  在函数内可以采用表达式形式的yield:

def eater():print('Ready to eat')while True:food=yieldprint('get the food: %s, and start to eat' %food)

  可以拿到函数的生成器对象持续为函数体send值:

g=eater() # 得到生成器对象
print(g) # <generator object eater at 0x101b6e2b0>>>>
print(next(g)) # 需要事先”初始化”一次,让函数挂起在food=yield,等待调用g.send()方法为其传值Ready to eat
g.send('包子') # get the food: 包子, and start to eat
g.send('鸡腿') # get the food: 鸡腿, and start to eat

  针对表达式形式的yield,生成器对象必须事先被初始化一次,让函数挂起在food=yield的位置,等待调用g.send()方法为函数体传值。

注意:

  1. g.send(None) 相当于 next(g)
  2. g.close() 关闭之后就不能再传值了

  可以编写装饰器来完成为所有表达式形式yield对应生成器的初始化操作:

def init(func):def wrapper(*args,**kwargs):g=func(*args,**kwargs)next(g)return greturn wrapper@init
def eater():print('Ready to eat')while True:food=yieldprint('get the food: %s, and start to eat' %food)

  表达式形式的yield也可以用于返回多次值,即 变量名=yield 值的形式:

def eater():print('Ready to eat')food_list=[]while True:food=yield food_listfood_list.append(food)e=eater()
print(next(e)) # Ready to eat[]
e.send('蒸羊羔') # ['蒸羊羔']
e.send('蒸熊掌') # ['蒸羊羔', '蒸熊掌']
e.send('蒸鹿尾儿') # ['蒸羊羔', '蒸熊掌', '蒸鹿尾儿']

列表生成式

  列表生成式是python为我们提供的一种简化代码的解决方案,用来快速生成列表,语法如下:

[expression for item1 in iterable1 if condition1
for item2 in iterable2 if condition2
#...
for itemN in iterableN if conditionN]#类似于
res=[]
for item1 in iterable1:if condition1:for item2 in iterable2:if condition2...for itemN in iterableN:if conditionN:res.append(expression)

  比如下面的案例:

egg_list=[]
for i in range(10):egg_list.append('鸡蛋%s' %i)# 用列表生成式可以一行解决
egg_list=['鸡蛋%s' %i for i in range(10)]

  下面是一个字典生成式:

keys = [1, 2, 3]print({key:None for key in keys })  # {1: None, 2: None, 3: None}keys = [('name', 'tom')]print({k: v for k,v in keys if k == 'name'})    # {'name': 'tom'}

注意:同理还存在集合生成式,但是没有元祖生成式。

生成器表达式

  创建一个生成器对象有两种方式,一种是调用带yield关键字的函数,另一种就是生成器表达式:

(expression for item in iterable if condition)

  对比列表生成式返回的是一个列表,生成器表达式返回的是一个生成器对象:

print([x*x for x in range(3)]) # [0, 1, 4]g=(x*x for x in range(3))print(g) # <generator object <genexpr> at 0x101be0ba0>

  对比列表生成式,生成器表达式的优点是节省内存(一次只产生一个值在内存中):

print(next(g)) # 0
print(next(g)) # 1
print(next(g)) # 4
print(next(g)0 #抛出异常StopIteration

  如果我们要读取一个大文件的字节数,应该基于生成器表达式的方式完成:

with open('db.txt','rb') as f:nums=(len(line) for line in f)total_size=sum(nums) # 依次执行next(nums),然后累加到一起得到结果

19-Python基础知识学习-----迭代器与生成器相关推荐

  1. python基础知识7——迭代器,生成器,装饰器

    迭代器 1.迭代器 迭代器是访问集合元素的一种方式.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退.另外,迭代器 ...

  2. Python基础知识学习笔记——Matplotlib绘图

    Python基础知识学习笔记--Matplotlib绘图 整理python笔记,以防忘记 文章目录 Python基础知识学习笔记--Matplotlib绘图 一.绘图和可视化 1.导入模块 2.一个简 ...

  3. python基础知识学习笔记(2)

    python基础知识学习笔记(2) 整理一下python基础知识,以防忘记 文章目录 python基础知识学习笔记(2) python简洁的一行代码 python简洁的一行代码 1.交换两个变量 # ...

  4. Python 基础知识学习笔记——NumPy

    Python基础知识学习笔记--NumPy 与 matlab 优秀的矩阵运算类似,python 提供了 numpy 库,这对熟悉 matlab 的用户来说非常友好.向量.矩阵和多维数组是数值计算中必不 ...

  5. Python 基础知识学习笔记——OpenCV(1)

    Python 基础知识学习笔记--OpenCV(1) OpenCV是一个开源的跨平台计算机视觉和机器学习软件库,它轻量而且高效,被广泛的使用. 整理一下OpenCV学习笔记,以防忘记. 文章目录 Py ...

  6. python基础知识学习笔记(1)

    python 基础知识学习笔记(1) 总结一下Python基础知识,以防忘记. 文章目录 python 基础知识学习笔记(1) 一.起步 1.python安装与编译环境 二.变量和简单数据类型 三.列 ...

  7. Python基础知识学习笔记(一)

    Python基础知识学习笔记(一) 文章目录 Python基础知识学习笔记(一) (一) 认识python 1.注释 2.变量及类型 3.关键字(标识符) (1)什么是关键字? (2)查看关键字 (3 ...

  8. python基础知识学习总结

    python基础知识学习总结 从零开始学习python,已经学习完python相关的基础教程,学习地址详见:http://www.runoob.com/python/python-tutorial.h ...

  9. 初学者入门级!Python基础知识学习,纯干货【建议收藏】

    注释方法 # 单行注释 ''' 多行注释 ''' 数据类型 关键字 名称 示例 chr 单个字符 '', 'd' str 字符串(多个chr) 'dd', '你好' int 整数 1,2,3,4 fl ...

最新文章

  1. 手机webapp meta标签 (全屏)
  2. python语言的翻译方式是什么-python自动翻译实现方法
  3. Datatable中对某列求和,三种不同情况下的方法 .
  4. Python函数Day1
  5. python raise_python raise 使用方法
  6. 达人探店小程序全套源码
  7. API和Web API(1)
  8. JavaScript的输出(2)
  9. Jquery之AJAX用户注册表单验证(Vancl版)
  10. [Linux] Ubuntu Server 12.04 LTS 平台上搭建WordPress(Nginx+MySQL+PHP) Part IV
  11. SMART Utility for mac (硬盘检测工具)
  12. 单片机c语言程序设计软件下载,《手把手教你学单片机C程序设计》PDF免费版下载...
  13. Enviropro EP100D-08测定仪
  14. 微信小程序即时通讯(融云sdk)
  15. Linux用SSH密匙登录
  16. java socket 读取文件_java中ServerSocket读取文件流不是分行读取
  17. 2018中文EI收录情况
  18. cuda9.2环境下pip安装tensorflow非官方轮子
  19. Sigil制作epub,正则表达式的使用
  20. Win10家庭版 误删winsock和winsock2注册表的解决方案

热门文章

  1. android倒计时动画特效,Android实现答题倒计时效果
  2. 目标和学习方法的重要性
  3. 【深度学习】基于人脸关键点的视频心率检测
  4. Image 图像转化为 PDF 文件
  5. 算法很美第一章 位运算的奇巧淫技
  6. 2005年10月--至今 开发过的项目
  7. 爱快路由器使用L2TP线路做出口
  8. iOS设备分辨率 UI规范 以及适配
  9. Anbox 编译和Anbox Docker 下编译运行
  10. armbian ubuntu 桌面_armbian安装lxde桌面