Python基础14-迭代器与生成器
目录
迭代器
官方文档对迭代器的解释
迭代器协议
基于迭代器协议的统一的for循环机制
生成器
官方文档对生成器的解释
生成器函数
生成器表达式
生成器用法举例
利用生成器用单线程实现生产者消费者问题模型
生成器只能遍历一次
迭代器
官方文档对迭代器的解释
This style of access is clear, concise, and convenient. The use of iterators pervades and unifies Python. Behind the scenes, the
for
statement callsiter()
on the container object. The function returns an iterator object that defines the method__next__()
which accesses elements in the container one at a time. When there are no more elements,__next__()
raises aStopIteration
exception which tells thefor
loop to terminate. You can call the__next__()
method using thenext()
built-in function; this example shows how it all works:
参考Python文档tutorial中9.8 iterator的内容。for循环在容器对象上调用iter函数,iter函数返回一个迭代器对象,迭代器对象定义了__next__方法。每调用一次__next__方法,就返回容器对象上的一个元素,如果不能返回下一个元素,那么会引发一个StopIteration异常,这样就通知for循环就终止了。
s = 'iterator'# 可迭代对象有__iter__方法返回迭代器
it = s.__iter__()
# 迭代器调用__next__方法返回下一个迭代的元素
print(it.__next__())
print(it.__next__())
print(it.__next__())
print(it.__next__())
print(it.__next__())
print(it.__next__())
print(it.__next__())
print(it.__next__())
# 引发StopIteration异常
print(it.__next__())
而for循环利用iter和next内置函数来调用被迭代对象的__iter__和__next__方法。
s = 'iterator'
# iter函数调用可迭代对象__iter__方法返回迭代器
it = iter(s)
# next函数调用迭代器__next__方法返回下一个迭代的元素
print(next(it))
print(next(it))
print(next(it))
print(next(it))
print(next(it))
print(next(it))
print(next(it))
print(next(it))
# 引发StopIteration异常
print(next(it))
迭代器协议
Having seen the mechanics behind the iterator protocol, it is easy to add iterator behavior to your classes. Define an
__iter__()
method which returns an object with a__next__()
method. If the class defines__next__()
, then__iter__()
can just returnself
:
迭代器协议就是官方文档对迭代器的解释。迭代器必须提供一个__next__方法,__next__方法返回迭代中的下一个对象,或者没有下一个对象时,引发一个StopIteration异常。
可迭代对象就是实现了迭代器协议的对象。具体实现方法也在官方文档中给出。就是对象定义一个__iter__方法,__iter__方法返回迭代器对象,迭代器对象必须定义__next__方法。如果类定义了__next__方法,那么__iter__方法就返回self。这个等研究面向对象时再具体分析。
官方文档的例子,定义了一个Reverse类,初始化一个字符串,倒叙迭代这个字符串。比如'spam’,for循环一个一个输出字符maps。
class Rs:def __init__(self, data):self.data = dataself.index = len(data)passdef __iter__(self):return selfdef __next__(self):if self.index == 0:raise StopIterationself.index -= 1return self.data[self.index]passrs = Rs('spam')
for i in rs:print(i)pass
基于迭代器协议的统一的for循环机制
我们有了while循环,我们可以用索引方式,遍历所有序列类型的对象。为什么要用for呢?因为有些遍历没法用索引方式,比如无序的集合set、字典dict。我们实现功能时,很可能创建的就是无序的对象,所以要用for。Python基于迭代器协议的统一的for循环机制就一劳永逸(希望是这样,干过开发的都知道,怎么可能一劳永逸?)的解决了这个问题。
生成器
官方文档对生成器的解释
Generators are a simple and powerful tool for creating iterators. They are written like regular functions but use the
yield
statement whenever they want to return data. Each timenext()
is called on it, the generator resumes where it left off (it remembers all the data values and which statement was last executed). An example shows that generators can be trivially easy to create:
参考Python官方文档9.9 Generator的内容。生成器可以理解为自动生成了迭代器的数据类型,因此生成器就是可迭代对象。生成器有两种形式,生成器函数和生成器表达式(9.10. Generator Expressions)。
生成器函数
生成器函数,不用return返回,用yield返回而且可以返回多次。
def test():yield 1yield 2yield 3passa = test()
print(type(a), a)
# <class 'generator'> <generator object test at 0x0000000003B50CF0>
print(next(a))
print(next(a))
print(next(a))
# StopIteration
print(next(a))
官方文档中也给出了一个生成器函数的用法。函数实现了返回生成器,反向逐个返回字符的迭代功能 ,注意yield的用法。
def reverse(data):for index in range(len(data) - 1, -1, -1):yield data[index]# rotareneg
for i in reversed('generator'):print(i, end='')pass
生成器表达式
Some simple generators can be coded succinctly as expressions using a syntax similar to list comprehensions but with parentheses instead of square brackets. These expressions are designed for situations where the generator is used right away by an enclosing function. Generator expressions are more compact but less versatile than full generator definitions and tend to be more memory friendly than equivalent list comprehensions.
参考Python官方文档9.10 Generator Expressions。对于一些简单的生成器,可以用类似列表解析的语法格式来编程,只需要将列表解析的[]换成()即可。这种方式可以用于做闭包,目前还没研究,后面再研究。生成器表达式更轻量,但不能做太复杂的表述。生成器表达式不像列表解析那样消耗内存。
要理解这段话,先解释三元表达式,再解释列表解析,最后解释生成器表达式。
三元表达式,以下两种写法等价。
db = 'hana'
if db == 'hana':os = 'linux'
else:os = 'windows'pass
print(os)
# linuxdb = 'hana'
# 这就是三元表达式
# 条件在if和else之间,等式成立为if前面的值,不成立为else后面的值
os = 'linux' if db == 'hana' else 'windows'
print(os)
# linux
列表解析,可以利用三元表达式进行列表解析。此时生成的就是一个真实的列表,如果列表元素多,那么会占用大量的内存。
# 用三元表达式进行列表解析
# 生成的就是列表,如果列表很大会占用大量内存
n = [i for i in range(10)]
print(n)
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]n = [i for i in range(10) if i > 5]
print(n)
# [6, 7, 8, 9]
生成器表达式,此时得到一个生成器,不会占用大量内存。同时实现了用一个取出一个。
# 将列表解析的[]改为()就得到了生成器表达式
# 生成器表达式的值是个生成器,自带__iter__和__next__方法,用法和迭代器一样
# 但是,这里用一个返回一个,就算列表再大也不会占用太多内存
n = (i for i in range(10))
print(n)
n = (i for i in range(10) if i > 5)
print(next(n))
print(next(n))
print(next(n))
print(next(n))
# StopIteration
print(next(n))
生成器用法举例
举一个实用的例子。读取一个文件,获取所有单词逐个处理。我们可以把文件全部读进内存然后逐个处理。我们也可以用生成器读取一个单词进内存,然后处理,节约内存。
"""
Python is an easy to learn, powerful programming language. It has efficient
high-level data structures and a simple but effective approach to
object-oriented programming. Python’s elegant syntax and dynamic typing,
together with its interpreted nature, make it an ideal language for scripting
and rapid application development in many areas on most platforms.以上就是文件file8.txt的内容
"""f = open('file8.txt', mode='r', encoding='utf-8')# 将标点符号,.全部替换为空格
punctuation = ',.'
white = ' ' * len(punctuation)
trans_tab = str.maketrans(punctuation, white)# 全部读取到内存,再拆分放进列表words
data = f.readlines()
words = []
for line in data:words.extend(line.translate(trans_tab).split())pass
print(words)
f.close()
我们也可以不全部读进内存,使用for迭代,逐个处理。
f = open('file8.txt', mode='r', encoding='utf-8')
# 将标点符号,.全部替换为空格
punctuation = ',.'
white = ' ' * len(punctuation)
trans_tab = str.maketrans(punctuation, white)
# 用迭代的办法逐个处理
for line in f:for word in line.translate(trans_tab).split():print(word, end=' ')passpass
f.close()
我们最佳的办法是,用迭代器表达式。用一个单词,读取一个单词,逐个处理。
f = open('file8.txt', mode='r', encoding='utf-8')
# 将标点符号,.全部替换为空格
punctuation = ',.'
white = ' ' * len(punctuation)
trans_tab = str.maketrans(punctuation, white)
# 拿到生成器
word_g = (word for line in f for word in line.translate(trans_tab).split())
# 逐个处理单词
for word in word_g:print(word, end=' ')
f.close()
或者,我们用函数返回一个生成器,逐个单词处理,这样可能看的更清楚一点。
def get_word_g(file, punctuation='.,', encoding='utf-8'):white = ' ' * len(punctuation)trans_tab = str.maketrans(punctuation, white)# 这是另一种打开文件的写法,好处是不用关闭文件,自动关闭with open(file, 'r', encoding=encoding) as f:for line in f:for word in line.translate(trans_tab).split():yield wordpasspasspasspasswg = get_word_g('file8.txt', punctuation='.,')
for w in wg:print(w)
利用生成器用单线程实现生产者消费者问题模型
这个问题本身应该用多线程实现的。这里只是用来说一下yield的用法。生成器函数有yield,那么函数被调用的时候返回一个生成器,函数体并不会真正执行。只有当next调用或者被send的时候才会执行,执行到yield就又停止执行了。send的内容会被yield传入。
import timedef consumer(name):print('i am %s, i am ready to eat' % name)while True:food = yieldtime.sleep(0.1)print('%s eat %s' % (name, food))passpassdef producer():c1 = consumer('Kevin')c1.send(None)for i in range(10):time.sleep(0.2)food = 'bread.%s' % iprint('producer make %s' % food)c1.send(food)passproducer()
生成器只能遍历一次
生成器只能遍历一次,不仅仅是显示的for循环调用,next调用,还有不明显的max、min、sorted、sum等内置函数也会这样。所以要注意!!!
def test():for i in range(4):yield ipasspasst1 = test()
t2 = (i for i in t1)
print(list(t1))
print(list(t2))
# 生成器只能遍历一次,一次以后就没有迭代作用了
# 所以结果是
# [0, 1, 2, 3]
# []
以内置函数sum为例,说明一下。
def test():for i in range(4):yield ipasspasst1 = test()
t2 = (i for i in t1)
print(sum(t1))
print(list(t2))
# 生成器只能遍历一次,一次以后就没有迭代作用了
# 所以结果是
# 6
# []
再以map为例说明,reduce、filter等也要注意。如果只是用了map,map返回的是map对象,这不会触发生成器迭代操作,但是如果map返回对象被使用了,那么情况就不一样了。下面两段代码请仔细对比。
def test():for i in range(4):yield ipasspasst1 = test()
t2 = (i for i in t1)
print(map(lambda x: x ** 2, t1))
print(list(t2))
# map只是返回map对象,生成器没有遍历,所以结果是
# <map object at 0x0000000001EBFF10>
# [0, 1, 2, 3]
def test():for i in range(4):yield ipasspasst1 = test()
t2 = (i for i in t1)
print(list(map(lambda x: x ** 2, t1)))
print(list(t2))
# map只是返回map对象,生成器被list调用时遍历,所以结果是
# [0, 1, 4, 9]
# []
相关文章:

Android学习笔记进阶九之Matrix对称变换
网上很多的倒影特效实际上就是一个对称变换,在改变透明度即可。 Matrix对称变换包括很多种,有关于Y轴对称,关于X轴对称,关于y -x对称等等。 1 关于Y轴对称 [java] view plaincopy// 获取资源文件的引用res Resources res…

《计算机网络应用基础》模拟试卷(六),《计算机与网络应用基础知识1》模拟试卷...
《计算机与网络应用基础知识1》模拟试卷 (4页)本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦!9.9 积分《计算机与网络应用基础知识1》模拟试卷 一考生注意:1.本试卷共五道大题&…

ios架构篇-1 项目组织架构
关键字:项目组织架构 CocoaPod + 多项目级联 + xib + MVVM ProjectApp 项目app project Vendor 第三方.a、.framework库或源码 Resources 项目静态配置文件 Database 数据库文件夹,如CoreData Component 此项目特定的组件 Base 此项目…

Error 0162 - Setup data integrity check failure after updating BIOS via Thinkvantage
Start the computer and start pressing F1 and get into set up. In setup press F9 for default settings and press F10 for svae and exit. Problem solved. 转载于:https://www.cnblogs.com/gaoshaonian/p/9700130.html

CV00-02-CV基本操作1
目录 数字图像属性 opencv-python环境搭建 基本操作I Read in / Show out,读取、显示图像; Change color,修改颜色; Gamma Correction,伽马校正; Crop,切割; Histogram&…

链式表的按序号查找
本题要求实现一个函数,找到并返回链式表的第K个元素。 函数接口定义: ElementType FindKth( List L, int K );其中List结构定义如下: typedef struct LNode *PtrToLNode; struct LNode {ElementType Data;PtrToLNode Next; }; typedef PtrToL…

Codeforces Round #409 (Div. 2) C Voltage Keepsake(二分)
题意:有n(n<100000)个机器。。。第i个机器最开始有bi(1<bi < 100000)个单位的电量,机器可以储存的电量没有上限,启动后每秒消耗ai(1<ai<100000)个单位的电量,有一个充电器每秒可以充p(1<p<1e9)的电量。求保持所有机器电…

电子计算机的发展与应用教案,川教版信息技术七上第3课《电子计算机的发展与应用》教案1.doc...
川教版信息技术七上第3课《电子计算机的发展与应用》教案1整理双流县中学现代课堂教学分课时教学设计课题第3课 计算机的发展与应用课时1课型新课教学目标知识与能力:了解计算机的产生和发展,了解我国计算机的发展状况,计算机的特点与具体应用…

ios架构篇-2 国际化多语言
关键字:ios,国际化,多语言 实现功能: 1.默认采用系统语言 2.语言切换后实时生效 3.支持中英文,包含页面、app名称、系统默认权限弹框(如相机相册权限) 思路:app首次初始设置为系统语言,用户在app内切换语言时发送语言切换通知,刷新所有页面 1.project增加需要支持的…

Python基础15-函数闭包与装饰器
目录 装饰器概念 装饰器的实现 修改被装饰函数的代码(非装饰器实现) 修改被装饰函数的调用方式(非装饰器实现) 装饰器的实现(不完整的实现level1) 装饰器实现的语法糖(不完整的实现level2…

python 全栈开发,Day132(玩具管理页面,控制玩具通讯录,基于请求的好友关系建立)...
先下载github代码,下面的操作,都是基于这个版本来的! https://github.com/987334176/Intelligent_toy/archive/v1.5.zip 注意:由于涉及到版权问题,此附件没有图片和音乐。请参考链接,手动采集一下ÿ…

iOS技术篇1-CocoaPods
iOS技术篇1-CocoaPods 上一篇: 目录 下一篇:ios技术篇2-CoreData

计算机艺术未来发展趋势,计算机技术对现代艺术设计的影响
摘 要 在当今,计算机技术已经覆盖到了全球生活的各个领域,毫不夸张地说,计算机技术已经成为世界上最重要的技术之一。计算机技术对于某些行业和领域的冲击是巨大的,甚至是革命性的改变,它能够使很多的活动变得更为便捷…

【JZOJ5064】【GDOI2017第二轮模拟day2】友好城市 Kosarajo算法+bitset+ST表+分块
题面 在Byteland 一共有n 座城市,编号依次为1 到n,这些城市之间通过m 条单向公路连接。 对于两座不同的城市a 和b,如果a 能通过这些单向道路直接或间接到达b,且b 也能如此到达a,那么它们就会被认为是一对友好城市。 By…

Python基础16-模块与包基础01
目录 初识模块和包 Python常用的内置模块 关键字import和from import、from查找的路径 如何调用 __name__与模块执行 __name__的用法(单元测试) 初识模块和包 我们把功能相近或相关的py文件组成模块,这样分开写代码便于维护,…

配置用户通过Telnet登录设备的身份认证(AAA本地认证)
背景信息 用户通过Telnet登录设备时,设备上必须配置验证方式,否则用户无法成功登录设备。设备支持不认证、密码认证和AAA认证三种用户界面的验证方式,其中AAA认证方式安全性最高。 采用AAA本地认证方式实现用户通过Telnet登录设备的身份认证&…
【自考】信息系统开发与管理(二)——章节详读
自考的第二阶段结束了,这一阶段是对书的详读过程。每章节读完,画一个导图。将其总结成一张网。织网的过程就是思考的过程。织网不断进行中……!宏观方面:1~3章第一章 管理信息系统导论在研究一…

ios技术篇-CoreData
ios技术篇-CoreData 上一篇: iOS技术篇-CocoaPods 目录 下一篇:

中山大学计算机学院运动会,喜讯!我院获2019中大校运会教工组团体第二名
11月2日,中山大学2019年运动会在南校园举行,来自全校68个院系、附属医院、部门共3200余名师生参加比赛。由37名职工运动员组成的中山七院代表队参加教工组田径赛、趣味田径及球类等全部15项比赛,经过激烈角逐,最终以团体总分173分…

Python基础17-模块与包基础02、常用模块之time、random
目录 名字冲突与避免 设置BASE_DIR保证程序能找到模块位置 time random 名字冲突与避免 在test.py里写下面一段代码,用正则表达式包re进行匹配,匹配出123开头的字符。如果我们在test.py同级写一个re.py,那么Python解释器在进行导入时就会…

Hadoop学习笔记(1) ——菜鸟入门
Hadoop学习笔记(1) ——菜鸟入门 Hadoop是什么?先问一下百度吧: 【百度百科】一个分布式系统基础架构,由Apache基金会所开发。用户能够在不了解分布式底层细节的情况下。开发分布式程序。充分利用集群的威力进行快…

HTTP协议简介
HTTP协议HTTP协议简介 超文本传输协议(英文:HyperText Transfer Protocol,缩写:HTTP)是一种用于分布式、协作式和超媒体信息系统的应用层协议。HTTP是万维网的数据通信的基础。 HTTP的发展是由蒂姆伯纳斯-李于1989年在…

计算机组成原理读写周期波形图,第3章存储器层次结构-1讲述.ppt
第3章存储器层次结构-1讲述计算机组成原理 * 计算机组成原理 ——存储器层次结构(1) 2016-3-18 几个基本概念 1、存储器:计算机系统中的记忆设备,用来存放程序和数据。 2、存储元:存储器的最小组成单位,用以存储1位二进制代码。 3…

iOS架构篇-4 架构模式MVVM
iOS架构篇-4 架构模式MVVM MVVM原理MVVM 登录例子View:ViewModel:Model:如果觉得可以就点个👍吧,欢迎粉丝收藏,土豪打赏,您的关注就是我们创作的动力!读者有什么想看的相关技术篇章,欢迎评论留言!QQ交流群:908058499MVVM原理 #mermaid-svg-s6n4t9QkR9OeNy45 .label{fon…

CV00-01-开篇与环境搭建
目录 Intro 环境搭建 TensorFlow搭建 PyTorch搭建 PaddlePaddle搭建 Intro 从今天起学习CV,为期6个月,以三个真实项目为背景学习CV。 目前是第一个项目——车道线检测。时间两个月(共8周),每周五、周日晚上在线…

Spring MVC环境中的文件上传功能实现
在实际开发过程中,尤其是web项目开发,文件上传和下载的需求的功能非常场景,比如说用户头像、商品图片、邮件附件等等。其实文件上传下载的本质都是通过流的形式进行读写操作,而在开发中不同的框架都会对文件上传和下载有或多或少的…

iOS架构篇-5 CI/CD(持续集成、持续交付、持续部署)
iOS架构篇-5 CI/CD(持续集成、持续交付、持续部署) CI CI是指持续集成,代码的更新会定期自动构建、测试并合并到公共仓库中,方便多分支时解决冲突问题 CD CD是指持续交付和/或持续部署,开发人员改动代码会自动测试提交到仓库,运维实施人员将其部署到生产环境中,方便部…

计算机函数模式的用处是啥,请问怎么理解计算机中的函数?
你的理解有点外行看热闹的意思,呵呵。代码本身就是抽象的,所以“计算机中的函数是一种对代码进行抽象的方式”不能说不对,但是也和没说一样。至于“我们使用抽象出来的函数,而不用关心函数里面的代码是如何组织的”,只…

CV00-03-CV基本操作2
基本操作2 Similarity Transform相似变换 Similarity Transform相似变换:图像形状大小不变,位置发生变化。比如:做平移、旋转。相似变换具有保角性、保比例性,经过相似变换以后原有的角度和比例保持不变。确定一个相似变换矩阵需…

[LeetCode] [C++] 第一轮刷题总结(持续更新~~~)
LeetCode 解题报告 LC_1_解题报告LC_2_解题报告LC_3_解题报告LC_4_解题报告LC_5_解题报告LC_6_解题报告LC_7_解题报告LC_206_解题报告LC_237_解题报告LC_344_解题报告 LeetCode 1. Two Sum 解题思路:两次循环遍历数组,找到两个元素和等于target 注意点&…