四:迭代器生成器
Posted gyxpy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了四:迭代器生成器相关的知识,希望对你有一定的参考价值。
1.迭代器
1.1循环获取或者生成数据
1.2有__iter__()方法的对象就是可迭代对象,可以被for循环
1.3有__iter__()和__next__()方法的对象是迭代器对象
1.4for循环的原理:
- 获取可迭代对象的迭代器
- 循环调用迭代器的__next__()方法,直到没有值抛出StopIteration异常
- for循环抓住此异常,偷偷处理了,外部无感知
1.5自定义迭代器:借助已经存在的可迭代数据结构,__next__是已经封装好的逻辑,
class Students: stu_list=[] position = 0 def __init__(self,*args): for name in args: self.stu_list.append(name) def __iter__(self): return self def __next__(self): if self.position < len(self.stu_list): item = self.stu_list[self.position] self.position+=1 return item raise StopIteration() def append_stu(self,student): self.stu_list.append(student) stus = Students("张三","李四","王五") stus.append_stu("老王") for i in stus: print(i)
自定义迭代器对象,内部主要完成的是__next__方法如何拿到数据.
很少自己写迭代器,因为给你的数据类型完全够用,且__next__用c语句已经写好了内部逻辑,可以不依赖索引来获取数据十分方便,就连列表也不用索引迭代获取数据了.
总结:迭代器里面多了三个方法
iter_l = [1,2,3,4,5,6].__iter__() #获取迭代器中元素的长度 print(iter_l.__length_hint__()) #根据索引值指定从哪里开始迭代 print(‘*‘,iter_l.__setstate__(4)) #一个一个的取值 print(‘**‘,iter_l.__next__()) print(‘***‘,iter_l.__next__())
可见列表的迭代器底层用的索引在迭代数据,只是对调用者隐藏了细节,只知道调用__next__就可以获取下一个值.
字符串.列表.元组.都有下标,set.dict没有下标,迭代器把无论是否有下标的数据类型迭代数据全部进行了统一,这样用for就可以轻松遍历他们,很舒服.
2.生成器
常用来作为生成数据的工具,本质是迭代器,自带了__iter__和__next__不用我们实现了,只需要关注生成逻辑即可.
往往生成的数据量很大
def num_gen(): num=0 while True: yield num num+=1 g = num_gen() for i in g: print(i)
惰性运算,开发者自定义
2.1生成数据的逻辑一致------------生成器表达式
类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表
2.2生成数据的逻辑随着条件不同产生数据不同---------------生成器函数
常规函数定义,但是,使用yield语句而不是return语句返回结果。
yield的作用:1返回值,2挂起函数状态
yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次重它离开的地方继续执行
生成器函数调用内部逻辑不会执行,而是得到一个对象,里面保存着生成数据的逻辑,给一鞭子__next__()才会走一步,直到抛出StopIteration异常
def gen_test(): for i in range(20): yield "test%s" % i g = gen_test() #调用生成器函数得到生成器,只有间接或直接调用__next__()才会执行生成器函数 #执行到下一个yield #迭代生成器不断的从yield返回值到全局,实现一边生产一边获取值 for i in g: print(i)
主动前进的方式很少见,基本都是被动或者隐藏调用
for循环拿到迭代器,就是生成器
for i in range(5):
print(i)
用的就是生成器,只不过索引赋予了含义就是生成器中产生的值.
def averager(): total = 0.0 count = 0 average = None while True: term = yield average total += term count += 1 average = total/count g_avg = averager() next(g_avg) print(g_avg.send(10)) print(g_avg.send(30)) print(g_avg.send(5))
def init(func): #在调用被装饰生成器函数的时候首先用next激活生成器 def inner(*args,**kwargs): g = func(*args,**kwargs) next(g) return g return inner @init def averager(): total = 0.0 count = 0 average = None while True: term = yield average total += term count += 1 average = total/count g_avg = averager() # next(g_avg) 在装饰器中执行了next方法 print(g_avg.send(10)) print(g_avg.send(30)) print(g_avg.send(5))
以上是关于四:迭代器生成器的主要内容,如果未能解决你的问题,请参考以下文章