• 生成器
  • 生成器

    生成器

    1. 什么是生成器?

    生成器的本质就是迭代器,在python社区中,大多数时候都把迭代器和生成器是做同一个概念。唯一的不同就是:迭代器都是Python给你提供的已经写好的工具或者通过数据转化得来的,比如文件句柄,iter([1,2,3])。生成器是需要我们自己用python代码构建的工具。

    2. 生成器的构建方式

    1 生成器函数

    在生成器中,我们可以通过yield返回数据,而不是return, return会结束程序,而yield只是生成一个对象,等待你来取。但你可以理解为return.

    def fun():
        print('one')
        yield 11
        yield 22
    
    ret = fun()
    print(ret.__next__())
    

    当代码执行时,首先会打印one,然后将第一个yield的值交给ret(可以理解为return),此时它会保留状态,下次再取则从第一个yield之后取。如果再次执行print(ret.__next__())则会取到第二个yield之后 的值,即 22。

    总结:yield与return的区别: return一般在函数中只设置一个,他的作用是终止函数,并且给函数的执行者返回值。 yield在生成器函数中可设置多个,他并不会终止函数,next会获取对应yield生成的元素

    send

    send用来向生成器中传值,它本身包含next方法,看下面的例子:

    def gen(name):
        print(f'{name} ready to eat')
        while 1:
            food = yield
            print(f'{name} start to eat {food}')
    
    dog = gen('alex')
    next(dog)
    # 还可以给上一个yield发送值
    dog.send('骨头')
    dog.send('狗粮')
    dog.send('香肠')
    """
    alex ready to eat
    alex start to eat 骨头
    alex start to eat 狗粮
    alex start to eat 香肠
    """
    

    首先,next会将程序执行到yield,但上面next并不会打印出什么,(把yield理解为return,即即程序执行到yield返回了,没有赋值,但保留了状态,等待下一次从赋值开始)。随后的send将值传入,而程序从上次的状态接着执行,即赋值操作:foo='骨头', 所以我们看到的是:"alex start to eat 骨头"

    send() vs next() 我们看下官方文档:

    generator.send(value) 恢复执行并向生成器函数“发送”一个值。value 参数将成为当前 yield 表达式的结果。 send() 方法会返回生成器所产生的下一个值,或者如果生成器没有产生下一个值就退出则会引发 StopIteration。

    当调用 send() 来启动生成器时,它必须以 None 作为调用参数,因为这时没有可以接收值的 yield 表达式。

    相同: 1. 生成器对应的yield向下执行一次 2. 获取yield生成的值

    不同: 1. 第一次取yield的值时只能用next,如果非要用send,必须要send(none) #因为没有yield语句来接收这个值

    yield from

    当使用 yield from 时,它会将所提供的表达式视为一个子迭代器。 这个子迭代器产生的所有值都直接被传递给当前生成器方法的调用者。 通过 send() 传入的任何值以及通过 throw() 传入的任何异常如果有适当的方法则会被传给下层迭代器。 如果不是这种情况,那么 send() 将引发 AttributeError 或 TypeError,而 throw() 将立即引发所传入的异常。

    def fun():
        yield ['a', 'b', 'c']
    
    
    f = fun()
    print(f.__next__())
    

    这种情况下,会直接返回整个列表,但如果使用yield from 就会返回列表中单个元素。

    2 推导式
    gen = (i**2 for i in range(10))
    

    上一篇:协程

    下一篇:Pipenv 简单使用