zoukankan      html  css  js  c++  java
  • 8、【转载】python enhanced generator - coroutine

    本文转载自:http://www.cnblogs.com/xybaby/p/6323358.html

    正文

      本文主要介绍python中Enhanced generator即coroutine相关内容,包括基本语法、使用场景、注意事项,以及与其他语言协程实现的异同。

    enhanced generator

      在上文介绍了yield和generator的使用场景和主意事项,只用到了generator的next方法,事实上generator还有更强大的功能。PEP 342为generator增加了一系列方法来使得generator更像一个协程Coroutine。做主要的变化在于早期的yield只能返回值(作为数据的产生者), 而新增加的send方法能在generator恢复的时候消费一个数值,而去caller(generator的调用着)也可以通过throw在generator挂起的主动抛出异常。

      首先看看增强版本的yield,语法格式如下:
      back_data = yield cur_ret

      这段代码的意思是:当执行到这条语句时,返回cur_ret给调用者;并且当generator通过next()或者send(some_data)方法恢复的时候,将some_data赋值给back_data.For example:

    # -*- coding: utf-8 -*-
    
    def gen(data):
        print('before yield', data)
        back_data = yield data
        print('after resume', back_data)
    
    if __name__ == '__main__':
        g = gen(1)
        print(next(g))
        try:
            g.send(0)
        except StopIteration:
            pass

    输出:
    before yield 1
    1
    after resume 0

    两点需要注意

    (1) next() 等价于 send(None)
    (2) 第一次调用时,需要使用next()语句或是send(None),不能使用send发送一个非None的值,否则会出错的,因为没有Python yield语句来接收这个值。

    应用场景

      当generator可以接受数据(在从挂起状态恢复的时候) 而不仅仅是返回数据时, generator就有了消费数据(push)的能力。下面的例子来自这里:

    # -*- coding: utf-8 -*-
    
    word_map = {}
    def consume_data_from_file(file_name, consumer):   #此处consumer是consume_words这个generator!!!
        with open(file_name, 'r',encoding='utf-8') as file:
            for line in file.read():
                consumer.send(line)
    
    def consume_words(consumer):   #此处consumer是count_words_consumer这个generator!!!原因在于参数类型
        while True:
            line = yield
            for word in (w for w in line.split() if w.strip()):
                consumer.send(word)
    
    def count_words_consumer():
        while True:
            word  = yield
            if word not in word_map:
                word_map[word] = 0
            word_map[word] += 1
        print(word_map)
    
    if __name__ == '__main__':
        cons = count_words_consumer()
        next(cons)     #start generator
        cons_inner = consume_words(cons)   #注意此标红处,将count_words_consumer这个generator作为参数传入consume_words,
        next(cons_inner)      #start generator
        c = consume_data_from_file('D://header.txt', cons_inner)
        print(word_map)

          上面的代码中,真正的数据消费者是count_words_consumer,最原始的数据生产者是consume_data_from_file,数据的流向是主动从生产者推向消费者。不过上面__main__ 中分别调用了两次next启动生成器,这个可以使用一个decorator封装一下。

    def consumer(func):
        def wrapper(*args,**kw):
            gen = func(*args, **kw)
            next(gen)
            return gen
        return wrapper

    修改后的代码

    # -*- coding: utf-8 -*-
    
    def consumer(func):
        def wrapper(*args, **kw):
            gen = func(*args, **kw)
            next(gen)
            return gen
        return wrapper
    
    word_map = {}
    def consume_data_from_file(file_name, consumer):   #此处consumer是consume_words这个generator!!!
        with open(file_name, 'r',encoding='utf-8') as file:
            for line in file.read():
                consumer.send(line)
    
    @consumer
    def consume_words(consumer):   #此处consumer是count_words_consumer这个generator!!!原因在于参数类型
        while True:
            line = yield
            for word in (w for w in line.split() if w.strip()):
                consumer.send(word)
    
    @consumer
    def count_words_consumer():
        while True:
            word  = yield
            if word not in word_map:
                word_map[word] = 0
            word_map[word] += 1
        print(word_map)
    
    if __name__ == '__main__':
        cons = count_words_consumer()    #定位到wrapper,并在func中执行完yield语句后返回
        #next(cons)     #start generator
        cons_inner = consume_words(cons)   #定位到wrapper,并在func中执行完yield语句后返回
        #next(cons_inner)      #start generator
        c = consume_data_from_file('D://header.txt', cons_inner)
        print(word_map)

     

  • 相关阅读:
    怎么使用 Jupyter Notebook 进入指定的目录
    安卓手机安装Xposed框架/钉钉虚拟定位
    Some of the Example google dorks 2019谷歌hacker语法检索表
    在心脏内部,普通的WEB用户会怎样? 心脏滴血漏洞分析学习
    Windows的安全配置基础,打造一个安全点的Windows
    计算机存储单位
    Python如何安装whl文件,python安装py包
    jdk文件中javaw的作用
    msfconsole基础使用,简洁高效学习版
    VirtualBox报错:不能为虚拟电脑XXX打开一个新任务
  • 原文地址:https://www.cnblogs.com/zwb8848happy/p/8576203.html
Copyright © 2011-2022 走看看