Python迭代器和生成器的个人理解,再讲一讲协程

Posted 雪原那么远

tags:

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

  在认识yield的时候,网上很多文章都是说这个是个生成器,但是我并不知道这个是用来做什么的,所以概念很快就忘记了,后面读了几个文章以后感觉茅塞顿开。我就接介绍一下。

  有一篇文章提到,可以把yield看成是生成器的return的一部分,首先一个return的作用是在程序中返回某个值,返回之后程序就不再往下执行了,那么生成器是是什么,只有调用next()方法的时候该函数才会执行。结合来看,当一个函数带有yield,它已经不是一个函数了,而是一个生成器,即一个返回迭代器的函数,返回的迭代器有一个next方法,但是每次走一步,到yield停一次,下一次执行到next()时,再从上一次暂停的位置开始,直到执行到下一个yield表达式,将yield关键字后的表达式列表返回给调用者,并再次暂停。

  举个例子:

def run():
    print("starting...")
    while True:
        res = yield 1
        print("res:",res)

g = run()
print(next(g))
print("------")
print(next(g))

输入结果如下:
starting...
1
------
res: None
1

  上面的表达有点绕口,但是如果你懂迭代器,那么在这里你就懂了。如果不懂,也没关系,我将一下迭代器。

  迭代器的功能主要用于访问集合元素,迭代器从集合的第一个元素开始访问,知道所有元素被访问完结束。向我们的list,tuple,string,dict,都是可以迭代的,对于我们自己实现的类型,如果实现了__iter__()或者__getitem__()方法,那么该类对象也是可以迭代的。

  抽象来看的话,迭代器是一个数据流,对迭代器不断调用next()方法,就可以依次获取下一个元素,当迭代器没有元素的时候,调用next()会抛出StopIteration异常。iter()方法则返回一个特殊的迭代对象,当出现StopIteration异常的时候,则识别迭代完成结束。最常见的就是我们的for循环:

for i in range li:
    print(i)

  Python 处理for 循环时,首先会调用内建函数 iter(li),它实际上会调用 li.__iter__(),返回 li对应的迭代器。而后,li循环会调用内建函数 next(),作用在迭代器上,获取迭代器的下一个元素,并赋值给 x。这个时候,Python 才算是真正开始执行循环体。

  那问题来了,我们知道迭代器的用法,那生成器在什么地方可以用呢。那就不得不提到协程了。协程也叫微线程,举个例子:

  函数的调用都是层级调用,抽象来看是实现了栈的调用,a调用b,b调用c,那么c执行完毕返回,再b执行完毕返回,再a执行完毕。这里的调用顺序是明确的的。

  但是协程不同,虽然它也是子程序,但是在执行的过程中,子程序内部会发生中断,转而去执行别的子程序,在适当的时候再跳回来。

  那好处在哪里呢,线程的切换是需要开销的,而子程序的切换由程序自己控制,性能优势就有了。另外一个是因为只有一个线程,不存在读写冲突,在控制共享资源的时候不加锁,优势就更大了。

  正如前面所说的,yield能提供一个函数执行过程中的暂停,这个协程的子程序内部中断的思想不谋而合,如果使用协程去写生产者-消费者模型,那么当生产者生产消息以后,直接通过yield跳转到消费者开始执行,待消费者执行完毕以后,切换回生产者继续生产,效率极高:

import time

def consumer():
    r = ‘‘
    while True:
        n = yield r
        if not n:
            return
        print([CONSUMER] Consuming %s... % n)
        time.sleep(1)
        r = 200 OK

def produce(c):
    next(c) #廖雪峰这里是2.7版本,已经改为3.0版本
    n = 0
    while n < 5:
        n = n + 1
        print([PRODUCER] Producing %s... % n)
        r = c.send(n)
        print([PRODUCER] Consumer return: %s % r)
    c.close()

if __name__==__main__:
    c = consumer()
    produce(c)

 

参考:

廖雪峰讲协程

https://www.liaoxuefeng.com/wiki/897692888725344/923057403198272

python中yield的用法详解——最简单,最清晰的解释

https://blog.csdn.net/mieleizhi0522/article/details/82142856

Python3 迭代器与生成器

https://www.runoob.com/python3/python3-iterator-generator.html

Python 中的黑暗角落(一):理解 yield 关键字

https://liam.page/2017/06/30/understanding-yield-in-python/

什么是协程 ?

https://juejin.im/post/5d5df6b35188252ae10bdf42

 

以上是关于Python迭代器和生成器的个人理解,再讲一讲协程的主要内容,如果未能解决你的问题,请参考以下文章

python控制结构迭代器和生成器(个人笔记)

Python核心深入理解迭代器和生成器

python中迭代器和生成器。

python基础-迭代器和生成器

如何更好地理解Python迭代器和生成器

第十二篇:多任务之协程