迭代器和生成器
python学习初期,学习到for循环可以循环取出目标中的值,再对逐一取到的值进行后续操作,虽然知其用法,但是不知其原理
随着学习的深入,会接触到一个新‘术语’,迭代
迭代:迭代是重复反馈过程的活动,其目的通常是为了逼近所需目标或结果。每一次对过程的重复称为一次“迭代”,而每一次迭代得到的结果会作为下一次迭代的初始值
所谓迭代(个人解读):一篮子鸡蛋里有一个鹅蛋,鹅蛋在篮子里的任意一个地方,规定一次只能拿一颗蛋,直到拿到鹅蛋为止,迭代的目标就是要拿到鹅蛋,迭代就是拿蛋的过程,每一次拿蛋的动作都是一次迭代,而每次拿到的蛋都独一无二、拿一个少一个
可迭代对象:在容器(你可以理解为篮子)里,可逐一取出
那就引申出一个问题,在python中如何判断目标是否是可迭代对象呢?方法如下:
from collections import iterable print(isinstance('aaa',iterable))
就是这样了,判断给出的答案只有两个,非True即False,我英语不好,所以不要问为什么,记着就行了T-T
iterable 可迭代的
instance 情况 isinstance 判断目标是否是某已知数据类型
说完什么是迭代,和判断是否是可迭代对象的方法以后,终于可以开始说正主了orz...
一、迭代器(iterator)
如果一定要把迭代归类成一种计算或取值方法,那么常规选择都是便利的for循环
但是如果一定要指定一个特定的功能定式出来,那么就记住
如果某数据类型点儿出来的功能里,有‘__iter__’,那么此数据类型可迭代
迭代器,就是具体实施,实现一次一次迭代的工具~~so~~简单粗暴
li = [1,2,3] li.__iter__() #就这样,莫名其妙的,变成了迭代器,what?...so...我也不晓得为什么,可能就像藏族选活佛一样吧,找几个有灵性的小孩备选,选中的那个,经过授权,就成为了活佛... #那么可迭代对象只要穿上了‘双下iter’的衣服,就摇身一变,功能升级,变成了迭代器...
本质:目前就我所知,迭代器存在的目的是,因为本身是惰性运算,所以可以更好的节省内存,但功能和for没啥区别,还比for麻烦
迭代器的功能有二:‘__iter__’和‘__next__’,所以这也可以用于判断是否是迭代器,就看有没有这俩功能
迭代器有两种:
1,天生的,如:文件句柄
2,后天的,可迭代对象.__iter__()
二、生成器
生成器就是我们自己写出来的迭代器...(所以弄出来这么多拗口的概念是不是精神分裂,让我回想起了大学时让人恨的牙痒痒的那些人名,高斯、拉格朗日...)
生成器有两种:
1,生成器函数(顾名思义,写在函数里的,有迭代器功能的)
需要注意的:yield是标志,有它才是生成器(写两个以上yield就可以写成生成器,如果只有一个yield,麻烦还是不要脱裤子放屁了...)
yield的两项功能:⑴当return用,可以返回值⑵有个记账儿的小本儿,运行到哪下次继续
注意:生成器是个好人,内容只取一次,按顺序不回头,取完所有或人为写代码停止才停(简直任劳任怨,还不翻小肠)
示例:
1. def generator_func(): print(123) yield 'aaa' print(456) yield 'bbb' 2. def get_clothing(): for cloth in range(1,20000): yield '第%s件衣服'%cloth for i in range(50): print(get_clothing()) #稀里哗啦打印出50件~~~ for i in get_clothing(): print(i) if i == '第100件衣服': break #打印到100件的时候,人为叫停~~~
监视文件示例(广大女性的福音,是否可以发展成小程序,后台监控男朋友老公的聊天记录...):
import time #调用时间 def tail(filename): f = open(filename,encoding='utf-8') #读文件 f.seek(0,2) #光标找到文件末端 while True: #循环监视~~ line = f.readline() #一行一行的读取文件内容 if not line: #如果没啥内容 time.sleep(0.1) #0.1秒运行一次监视~~ continue #没啥内容就算了 yield line #返回文件新写入的内容 tail_g = tail('demo') #调用函数生成器,传入要监视的文件 for line in tail_g: print(line,end='') #好了,你想看的,都在这儿了...满意了么...
2.生成器表达式(内含列表推导式)
在此之前,需要说一下什么是列表推导式,以往我们在列表里取值,或想要对列表里的每一项进行一些操作的时候,都使用for循环
li = [1,2,3,4] for i in li: print(i) #那么是时候使用这种更言简意赅的表达方法了——列表推导式 写成: print([i for i in li])
注意:列表推导式需要放在列表中,尽量使用此写法简化代码,增强代码的可读性,切忌秀操作...
为什么要先插播列表推导式呢?
因为,所有的列表推导式都可以转化成生成器表达式,只需要把中括号换成小括号就OK,就是辣么简单~~~
一般情况下,建议都把列表推导式转化成生成器表达式,从而可以节省内存。
最后,附:
当把执行生成器的next换成send时,会传入生成器内值,此传入的值需要被接收,否则没啥用,若莫名其妙接收但没有传入值,接收的就是None
send和next工作的起止位置完全一样,在生成器开始执行的时候,必须要先next启动一下
若想send接收成功,需要在生成器中还有一个未被返回的yield
生成器预激装饰器:
def wrapper(func): def inner(*args,**kwargs): g = func(*args,**kwargs) next(g) return g return inner

浙公网安备 33010602011771号