• Python 8 协程


    1、用yield关键字和send方法实现简单的协程

    def simple_coroutine():                 # 携程使用生成器函数定义:定义题中有yield关键字
        print('-> coroutine started')       # 如果携程只从客户那里接受数据,那么产出的值是None,这个值是隐式的,因为yield关键字右边没有表达式
        x = yield
        print('-> coroutine received:', x)
    
    my_coro = simple_coroutine()
    print(my_coro)                          # 与创建生成器的方式一样,调用函数得到生成器对象
    next(my_coro)                           # 首先要调用next(..)函数,因为生成器还没有启动,没在yield语句初暂停,所以一开始无法发送数据
    
    my_coro.send(10)                        # 调用这个方法后,携程定义中的yield表但是会出现10,直到下一个yield出现或者终止

    以上代码结果为:

    <generator object simple_coroutine at 0x102a463b8>
    -> coroutine started
    -> coroutine received: 10
    Traceback (most recent call last):
        ...........                
        my_coro.send(10)                        # 调用这个方法后,携程定义中的yield表但是会出现10,直到下一个yield出现或者终止
    StopIteration

    如果yield未返回实际数据,则会返回None。send方法只可以把值赋给yield表达式,所以只有在协程暂停在yield的时候才可以send值,因此,必须先使用next激活协程,才可以send值,这一步称为“预激”。

    2、使用协程计算平均值

    from collections import namedtuple
    from functools import wraps
    
    Result = namedtuple('Result', 'count average')
    
    def coroutine(func):
        @wraps(func)
        def inner(*args, **kwargs):
            gen = func(*args, **kwargs)
            next(gen)
            return gen
        return inner
    
    @coroutine
    def averager():
        total = 0  # 总数
        count = 0  # 总个数
        average = None  # 平均值
        while True:
            term = yield
            if term is None:
                break
            total += term
            count += 1
            average = total / count
        return Result(count, average)
    
    a = averager()
    a.send(1)
    try:
        a.send(None)
    except StopIteration as e:
        result = e.value
        
    print(result)

    3.yield from关键字

    yield from 可以用来简化for循环:

    def gen():
        yield from 'AB'
        yield from range(10)

    用yield from当做委派生成器,这样就可以让多个任务并发的去处理,而不需要等待上一个任务完成。

    from collections import namedtuple
    
    
    Result = namedtuple('Result', 'count average')
    
    
    # 子生成器
    def averager():                                 # 子生成器
        total = 0.0
        count = 0
        average = None
        while True:
            term = yield                            # 通过main函数中的gourp.send()接收到term的值
            if term is None:                        # 至关重要的终止条件,告诉协程所有的数据已经结束,结束协程
                break
            total += term
            count += 1
            average = total/count
        return Result(count, average)               # 返回 grouper 中yield from的值
    
    
    # 委派生成器
    def grouper(results, key):                      # 委派生成器
        while True:                                 # 每次循环都会创建一个averager的实例
            results[key] = yield from averager()    # grouper发送的每个值都会让yield from处理,把产出的值绑定给resuluts[key]
    
    
    # 客户端代码,即调用方
    def main(data):                                 # main函数是客户端代码
        results = {}
        for key, values in data.items():
            group = grouper(results, key)           # group是调用grouper的生成器
            next(group)                             # 预激group协程
            for value in values:
                group.send(value)                   # 把各个value的值传递给grouper,通过grouper传入averager中term
            group.send(None)                        # 所有值传递结束以后,终止averager
        #print(results)                             # 如果要调试,去掉注释
        report(results)
    
    #输出报告
    def report(results):
        for key, result in sorted(results.items()):
            group, unit = key.split(';')
            print('{:2} {:5} averaging {:.2f}{}'.format(
                  result.count, group, result.average, unit))
    
    
    data = {
        'girls;kg':
            [40.9, 38.5, 44.3, 42.2, 45.2, 41.7, 44.5, 38.0, 40.6, 44.5],
        'girls;m':
            [1.6, 1.51, 1.4, 1.3, 1.41, 1.39, 1.33, 1.46, 1.45, 1.43],
        'boys;kg':
            [39.0, 40.8, 43.2, 40.8, 43.1, 38.6, 41.4, 40.6, 36.3],
        'boys;m':
            [1.38, 1.5, 1.32, 1.25, 1.37, 1.48, 1.25, 1.49, 1.46],
    }
    
    if __name__ == '__main__':
        main(data)
  • 相关阅读:
    CF1515G
    杂题
    ARC120E
    CF1528F
    ICPC2021银川C
    gym102129F
    杂记6.15
    杂记5.12
    杂记4.1
    杂记3.17
  • 原文地址:https://www.cnblogs.com/yinwenjie/p/10847514.html
Copyright © 2020-2023  润新知