生成器

# 首先必须区分迭代器(Iterator)和可迭代对象(Iterable)
"""
1、可迭代对象(Iterable):
    一类是集合数据类型,如 list 、 tuple 、 dict 、 set 、 str 等;
    一类是生成器对象,包括生成器和带 yield 的generator function。
    可迭代对象可以使用for循环遍历
2、迭代器(Iterator):
    可以被next()函数调用并不断返回下一个值的对象称为迭代器对象。
3、生成器对象是迭代器对象,可迭代对象不一定是迭代器对象
4、可以使用iter()函数将可迭代对象转为迭代器对象
"""

# 为什么有了列表生成式,还需要生成器呢?当我们使用列表生成式,list = [x for x in range(100000000)]时
# 还能得到一个正确的list吗?不能!!一次性生成了100000000个数,这些数把内存空间都占满了,程序还怎么运行啊!
# 所以生成器就是为了解决这么一个事而出现的。
# 生成器是什么?
# 生成器里面存放的是生成数字的一套规则(算法),返回的是一个生成器对象,假如我们同样要100000000个数
# 生成器只存放生成这100000000个数的规则,当我们要取时,我就去拿,要拿多少由你定。


# 创建生成器方法一
# 第一种方法很简单,只要把一个列表生成式的 [ ] 改成 ( )
# 返回的list并不是一个列表,更不是一个元组,而是一个生成器对象
# 生成器保存的是算法,每次调用 next(G) ,就计算出 G 的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出 StopIteration 的异常
list = (x for x in range(10))
print(next(list), end="\t")
# 既然生成器也是可迭代对象,那么肯定也是可以使用for循环遍历的
for x in list:
    print(x, end="\t")
print()
print("*" * 60)


# 创建生成器方法二
# 带 yield 的 generator function
# 下面定义了斐波拉契数列的推算规则
def fib(times):
    n = 0
    a, b = 0, 1
    print("8888")
    while n < times:
        print("-----1-----")
        t = yield b
        print("-----2-----")
        a, b = b, a + b
        n += 1


F = fib(3)
print(next(F))
print(next(F))
print(next(F))
print("*" * 60)
# 让我们来理解一下上面那个程序,yield 到底是什么?
# F = fib(3)    这里是创建一个生成器对象F
# print(next(F))    next(F)才开始正式调用生成器的function
# 注意:遇到yield时,马上停止!!!程序不往下面走了,所以第一个next(F)只输出了888和-----1------
# 注意:next(F)有一个返回值,返回的值时yield后面的b
# 第二个next(F),从第一次停止的地方开始,所以不会在输出888了,输出-----2-----和-----1-----


# __next()__
# 使用__next()__方法也可以去除生成器中的值,和next(F)的效果是一样的
def fib(times):
    n = 0
    a, b = 0, 1
    print("8888")
    while n < times:
        print("-----1-----")
        t = yield b
        print("-----2-----")
        a, b = b, a + b
        n += 1


F = fib(3)
print(F.__next__())
print(F.__next__())
print(F.send("haha"))
print("*" * 60)

# send()
def fib(times):
    n = 0
    while n < times:
        temp = yield n
        print(temp)
        n += 1

F = fib(3)
print(next(F))
print(next(F))
print(F.send("haha"))
# 我们可以看到yield n这个整体会返回一个数给temp,未经过处理返回的数是None
# 我们可以F.send("haha"),这样yield n这个整理就会把发送的haha赋值给temp
# 注意:c.__next__()等价c.send(None),所以也要小心 StopIteration 异常
# 注意:第一次不能使用c.send("haha"),为什么呢?第一次你发送haha,但是程序第一次遇到yield的时候就停了,haha给谁呢?
# 所以第一次不能使用c.send("haha"),解决方法:使用c.send(None)或者使用c.__next__()

 

posted @ 2018-11-12 18:58  人工智能之路上的菜鸡  阅读(228)  评论(0编辑  收藏  举报