四:迭代器生成器

Posted gyxpy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了四:迭代器生成器相关的知识,希望对你有一定的参考价值。

1.迭代器

1.1循环获取或者生成数据

1.2有__iter__()方法的对象就是可迭代对象,可以被for循环

1.3有__iter__()和__next__()方法的对象是迭代器对象

1.4for循环的原理:  

  1. 获取可迭代对象的迭代器
  2. 循环调用迭代器的__next__()方法,直到没有值抛出StopIteration异常
  3. 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)
View Code

自定义迭代器对象,内部主要完成的是__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)
View Code

主动前进的方式很少见,基本都是被动或者隐藏调用

for循环拿到迭代器,就是生成器

取值的方式:for循环,数据类型强制转换(占内存,是一次性的取所有)、next方法
生成器最后一个yield后面的代码会执行但是结果是没有办法返回的,外面拿不到。
调用next()方法,让迭代器逻辑开始执行到yield停止
g.send()比next(g)多了传值进入生成器内部的功能,第一个send(None)因为执行到一地个yield不需要传值

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))
加上装饰器

 

以上是关于四:迭代器生成器的主要内容,如果未能解决你的问题,请参考以下文章

四:迭代器生成器

函数四--迭代器和生成器

Python学习笔记(四,迭代器生成器内置函数)

Python学习笔记四(迭代器生成器内置函数)

迭代器生成器面向过程

五 迭代器生成器