python3的迭代器、生成器/yield

最近在使用keras,发现yield频繁出现,在此做个yield有关知识的总结。(主要个人理解,以通俗易懂为主,不一定专业)

1、迭代器

区别于常见的list、tuple、dict等容器(直接将数据存放于内存中),迭代器在内存中仅仅存放产生数据的逻辑(实际数据在运行时动态生成)。

得到迭代器的几种方式:

(1)使用iter函数,可将常见容器转为迭代器,eg iter([1,2,3,4,5,6])。

(2)重写__iter__函数(可以省略)和__next__函数(必须有),自定义迭代器类,实例化得到迭代器对象,如下所示:

class MyIter():

    def __init__(self):
        ***
        pass

    def __iter__(self):
        return self

    def __next__(self):
        ***
        raise StopIteration
        ***
        return ***

2、生成器

生成器(generator)是一种特殊的迭代器,具备延迟计算性质,一般和yield关键字挂钩,即通过yield关键字得到生成器函数,生成器在使用时与迭代器类似,数据在运行中动态生成,直至全部数据生成为止。

eg:

def stus():
    name = yield "zhangsan"

    print("name = {}".format(name))
    name = yield "lisi"

    print("name = {}".format(name))
    name = yield "wangwu"

    print("name = {}".format(name))
    yield "last"


if __name__ == '__main__':
    s1 = stus()
    print(next(s1))
    print("")

    print(s1.send("-- lu --"))
    print("")

    print(s1.__next__())
    print("")

    print(s1.send("-- qiao --"))

上述代码运行结果如下: 

zhangsan

name = -- lu --
lisi

name = None
wangwu

name = -- qiao --
last

生成器既可以包含有限元素(如上所示),也可以包含无限元素(比如keras的数据产生机制【data_generator函数】)的。

(1)next(s1)等价于s1.send(None)

(2)生成器的send函数的作用:用于代表yield ***表达式,进行赋值操作【一般情况yield所在行是一个赋值表达式】。,比如上述的name = yield "zahngsan",s1.send("xixi"),那么"xixi"赋值给了name,同时获取下一个yield后面表达式的值

(3)在执行next或send函数之后,程序会"卡住"在yield **表达式行(yield关键字所在行,而非下一行,等待被send替换赋值或next直接跳过),不会继续执行,直至下一个next函数或send函数调用

(4)使用生成器表达式(区别于列表推导式,eg:[i for i in range(5)],这里是方括号)也可以产生generator:(i * 10 for i in range(3)),这里是圆括号。

(5)若迭代器已访问到末尾,仍继续访问,则会抛出如下:

    main()
  File "D:/zzc_learning/PycharmWorkspace/python_learning/yield_code.py", line 60, in main
    print(g.send(20))
StopIteration

 (6)生成器和迭代器均只能访问一次,重复访问会报错或获取不到数据,因为产生数据的逻辑代码已执行结束!

(7)和return的区别:return会停止和退出当前函数/代码块的执行,并返回给调用者;yield不会停止和退出当前代码,只是"卡住"等待下一次被执行!

-- over --

猜你喜欢

转载自blog.csdn.net/qm5132/article/details/82990221