迭代器与生成器
一、迭代器 Iterator
1、可迭代对象:str、list、tuple、set、dict、文件句柄,range
__iter__() 这个方法导致了数据类型的可迭代
检测一个对象是否可迭代:
from collections import Iterable print(isinstance('aaa',Iterable)) print(isinstance(123,Iterable)) 输出 True False
2、可迭代协议:只要包含了__iter__()方法的数据类型就是可迭代的
这是数据类型和python解释器定下来的协议
dir(对象),可以查看此类型的对象所有的方法
print(dir((1,3)) 输出:列表 ['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'count', 'index']
3、迭代器 iterator
就是实现了能从其中一个一个的取出值来
迭代器 不关心值的索引状态 (所以for循环才能循环字典,集合等)
for循环,在遍历之前,先调用对象的__iter__方法,将其转换成1个迭代器,然后用迭代器协议去实现循环访问
lst_iterator = [1,2,3].__iter__() #lst_iterator 就是一个迭代器(通过可迭代对象,用__iter__()方法,获得) print(lst_iterator) 输出 <list_iterator object at 0x00000203948C8710>
#天生就是迭代器的:比如文件句柄
#后天生成迭代器的:比如 可迭代对象.__iter__()
列表的迭代器跟 列表比起来,有哪些新的方法:
print(set(dir(lst_iterator))-set(dir([1,2,3])))
输出:
{'__next__', #一个一个取值
'__length_hint__', #获取迭代器中元素的长度
'__setstate__'} #根据索引值指定从哪里开始迭代
4、迭代器协议:
迭代器中拥有__next__ 和 __iter__ 方法
检测是否是迭代器:
from collections import Iterator lst_iterator = [1,2,3].__iter__() print(isinstance(lst_iterator,Iterator)) print(isinstance([1,2,3],Iterator)) 输出True False
在python中,学过的所有可以被for循环的 基本数据类型 都是可迭代的,而不是迭代器
文件句柄是 迭代器
range是可迭代对象,但不是迭代器,包含__iter__,没有__next__
for 可以是一个可迭代对象,也可以是一个迭代器
迭代器和可迭代对象之间的关系:
#迭代器包含可迭代对象,
#迭代器 = 可迭代对象.__iter__()
5、迭代器存在的本质是什么:
#1、能够对python中的基本数据类型进行统一的遍历,不需要关心每一个值分别是什么
#2、可以节省内存 ——惰性运算
用__next__实现一个for循环
lst_iterator = [1,2,3].__iter__() while True: try: print(lst_iterator.__next__()) except StopIteration: ##接收到异常错误,就怎么怎么样 break 输出:1 2 3
二、生成器 Generator
1、生成器
是自己写出来的,就是迭代器
# 生成器函数
yield / yield from
yield语句,一次返回一个结果,在每个结果中间,挂起函数状态,以便下次从它离开的地方继续执行。
def generator_func(): ###生成器函数 print(123) yield 'aaa' print(465) yield 'bbb' g = generator_func() ###生成一个迭代器g print(g) 输出:<generator object generator_func at 0x00000226D0EC0EB8> print(g.__next__()) 输出:123 aaa print(g.__next__()) 输出:456 bbb
#带yield关键字的函数,就是生成器函数
#生成器函数,在调用的时候,只返回一个生成器,不执行生成器函数中的内容
2、从生成器中取值:
#1、__next__ 有几个yield 就可以取几次
#2、for 循环取值,正常取 for i in g:
#3、其他数据类型强制转换, list (g) 返回1个列表,里面包含生成器的所有内容
#注意:调用生成器函数时,要先获取生成器,再进行next取值
生成器中的内容,只能取一个,且按顺序取值,没有回头路,取完为止
3、举例
①
def generator_func(): yield 123 yield 456
②
def get_clothing(): for cloth in range(1,500): yield "第%s件衣服" % cloth g = get_clothing() for i in range(50): #一下取出50件衣服(通过设定执行多少次yield来进行) print(g.__next__()) for i in g: #取出前多少件衣服 (通过判断yield出来的值,来判断是否继续进行) print(i) if i =="第100件衣服": break
③
def func1() for i in [1,2,3,]: yield i for j in 'ABC': yield j def func2() yield from [1,2,3] ##只有python3里有 yield from yield from 'ABC'
4、对文件输入的监控
import time def tail(): with open('tmp') as f: f.seek(0,2) #光标移动到最后 while True: line = f.readline() if not line: time.sleep(0.5) continue yield line g = tail() for i in g: print(i,end="")
5、生成器预激装饰器
def func(func): def inner(*args,**kwargs): g = func(*args,**kwargs) g.__next___() return g return inner