生成器

生成器是一类特殊的迭代器(既然是迭代器了,那么当然就是可迭代对象).自己就是.不需要写__iter__(),__next__()这两个方法.
自己天生就是迭代器.
仍然可以使用iter(),next() 方法.

分类:
列表推导式[]: ---> () 就是 生成器表达式 :():<generator:>

生成器里面存放的不是具体的数据,只是存放的是一个算法.
生成器表达式和列表推导式的异同:
不同: (表达式) [表达式]
-------------------|----------------------|---------------------
产生的对象              生成器对象            列表对象
  占用内存                    少                          多
-------------------|----------------------|---------------------
相同: 使用结果一致

方式1:生成器表达式 列表推导式的[] 换成()之后就是生成器
首先要理解 列表推推导式 --> 返回值是一个列表

方式2:生成器函数 含有yield 关键字

def fib(n):
    num1, num2 = 1, 1

    count = 0

    # 1.暂时挂起当前函数  将后面的值返回给调用生成器的地方
    yield 100  # 返回值
    # 2.当再次调用生成器函数的时候, 会恢复当前函数继续执行
    yield 101  # 返回值


if __name__ == '__main__':
    # 生成器函数调用   不会执行函数代码 唯一的目的就是:产生生成器对象
    f = fib(10)

    # 调用生成器<迭代器>,获取下一个元素的值
    print(next(f))
    print(next(f))

# 断点调试只适用于少量代码的时候,多的时候不管用

生成器计算斐波拉契:

def fib(n):
    num1, num2 = 1, 1
    count = 0
    while count < n:
        yield num1  # 可以返回多个值  yield 1,2,3
        count += 1
        num1, num2 = num2, num1 + num2
    return 1000


#  最后不需要raise StopIteration <生成器内部已经自动实现>
# 一般在生成器中不使用return关键字,一旦使用就会结束生成器的迭代过程
if __name__ == '__main__':
    f = fib(10)
    # for i in f:  可以取出多个值 for i,j in f:...
    #     print(i)

    # 如果需要获取生成器函数的最终返回值,需要捕获迭代的异常
    # while True:
    #     # 通过迭代器取出下一个元素的值<返回值>
    #     try:
    #         pass
    #     except Exception as e:
    #         print(e)
    #         break
    #     else:
    #         print(i)

"""send()唤醒生成器,可以传参数"""

send在唤醒生成器的时候传入参数:

"""
面试问:
yield的作用:

send()可以传参数,不能第一次使用

使用场景:在生成下一个的时候,从我 指定的位置<传入的参数>开始生成
通过传入的参数,控制生成器下一次生成的元素

"""
"""
唤醒生成器:
元素的值=next(生成器对象)
元素的值=生成器.send(数据)

异同:
    next是函数  send()是方法
    next不能传参数,send可以传入参数<通过传输不同的参数控制生成器执行的逻辑>
    第一次只能next,其余地方随意使用<参数的值只有yield可以接收,因为第一次的时候没有yield>
同:
    获取到下一个元素的值<迭代>


yield关键字作用:
    1.挂起当前函数代码,将后面的表达式返回,调用生成器的地方
    2.接收可能存在的参数,紧接着上次执行的地方继续往下执行

"""


def fib(n):
    num1, num2 = 1, 1
    count = 0
    while count < n:
        # send()发送的消息只有yield关键字才能接收
        ret = yield num1
        print('接收到的参数是:', ret)
        count += 1
        num1, num2 = num2, num1 + num2


if __name__ == '__main__':
    f = fib(10)
    # 在第一次调用生成器的时候必须使用next(),因为第一次的时候没有yield接收传入的参数
    # TypeError: can't send non-None value to a just-started generator
    # 意思就是不能在第一次的时候将非None的数据发送给生成器.
    # print(f.send(None))  这样就可以
    print(next(f))
    print(f.send(101))
    print(f.send(102))
    print(f.send(103))
    print(f.send(103))
    print(f.send(103))


"""
容器类型就是典型的可迭代对象.

典型的:意思就是通用的,肯定是,具有代表性的

生成器肯定是可迭代对象.反之不行

"""
原文地址:https://www.cnblogs.com/huaibin/p/12100223.html