Python—协程_1

参考资料

迭代器

  • 直接作用于for循环的叫可迭代对象,Iterable

  • 不但可以作用于for循环,还可以被next调用的,叫Itrator

  • 可以用isinstance判断

      from collections import Iterable
      l = [1,2,3,4]
    
      isinstance(l, Iterable)
    
      
      from collections import Iterator
      isinstance((x for x in range(10)), Iterator)
    
  • iterable和Iterator的关系,可以通过iter函数运算

      isinstance(iter('abc'), Iterator)
    

生成器

  • 一边循环一边计算的机制,generator
  • 是一个算法/函数, 每次条用next的时候计算下一个值,最后跑出StopIteration
  • 生成器创建:
    • 直接使用
     L = [x * x for x in range(10)]
            g = (x * x for x in range(10))
  • 函数中包含yield,则叫generator
  • next调用,遇到yield返回
def odd():
                print('step 1')
                yield 1
                print('step 2')
                yield(3)
                print('step 3')
                yield(5)
        
             def fib(max):
                n, a, b = 0, 0, 1
                while n < max:
                    print(b)
                    a, b = b, a + b
                    n = n + 1
                return 'done'
                
             def fib(max):
                n, a, b = 0, 0, 1
                while n < max:
                    yield b
                    a, b = b, a + b
                    n = n + 1
                return 'done'

协程

  • 历史

    • 3.4引入协程概念,用yield实现
    • 3.5 引入协程语法
    • 实现包asyncio,tornado, gevent
  • 定义:“协程 是为非抢占式多任务产生子程序的计算机程序组件,
    协程允许不同入口点在不同位置暂停或开始执行程序”。
    从技术的角度来说,“协程就是你可以暂停执行的函数”。
    如果你把它理解成“就像生成器一样”,那么你就想对了。

  • 使用:

    • yield关键字
    • send关键字
  • 案例v1

  • 协程的四个状态

    • inspect.getgeneratorstate(…) 函数确定,该函数会返回下述字符串中的一个:
    • GEN_CREATED:等待开始执行
    • GEN_RUNNING:解释器正在执行
    • GEN_SUSPENED:在yield表达式处暂停
    • GEN_CLOSED:执行结束
    • next预激(prime)
    • 完整执行过程
    • v2
  • 协程终止

    • 协程中未处理的异常会向上冒泡,传给 next 函数或 send 方法的调用方(即触发协程的对象)。
    • 终止协程的一种方式:发送某个哨符值,让协程退出。内置的 None 和Ellipsis 等常量经常用作哨符值==。
  • 异常

    • 客户段代码可以在生成器对象上调用两个方法

    • generator.throw(Exctpiton):

      致使生成器在暂停的 yield 表达式处抛出指定的异常。如果生成器处理了抛出的异常,代码会向前执行到下一个 yield 表达式,而产出的值会成为调用 generator.throw方法得到的返回值。如果生成器没有处理抛出的异常,异常会向上冒泡,传到调用方的上下文中。

    • generator.close()

致使生成器在暂停的 yield 表达式处抛出 GeneratorExit 异常。
如果生成器没有处理这个异常,或者抛出了 StopIteration 异常(通常是指运行到结尾),
调用方不会报错。如果收到 GeneratorExit 异常,生成器一定不能产出值,否则解释器会抛出RuntimeError 异常。生成器抛出的其他异常会向上冒泡,传给调用方。
- v03

  • yield from
    • 为了得到返回值,协程必须正常终止;
    • 然后生成器对象会抛出StopIteration 异常,异常对象的 value 属性保存着返回的值。from
    • yield from 从内部捕获StopIteration异常
    • 并且把StopIteration异常value属性子作为yield from表达式的返回值
    • v04
    • v05
    • 委派生成器
      • 包含 yield from 表达式的生成器函数
      • 委派生成器在 yield from 表达式处暂停时,调用方可以直接把数据发给子生成器。
      • 子生成器再把产出的值发给调用方。
      • 子生成器返回之后,解释器会抛出 StopIteration 异常,并把返回值附加到异常对象上,
        此时委派生成器会恢复。
      • v06
**v01**
def continued():
    print("--> start")
    x = yield#遇到yield返回,返回的是空
    print("--> end",x)

sc = continued()
print(111)
#sc.send(None)效果一样
next(sc)#预激
print(222)
sc.send("weiwei")#赋值给x

# 结果:
# 111
# Traceback (most recent call last):
# --> start
# 222
# --> end weiwei
#   File "D:/Python/Python项目/基础学习/7-15/v01.py", line 11, in <module>
#     sc.send("weiwei")#赋值给x
# StopIteration

**v02**
def continued(a):
    print("--> start")
    b = yield a
    print("--> receive ",a,b)
    c = yield a+b
    print("--> receive ",a,b,c)

se = continued(5)
aa = next(se)##接收yield的返回值
print(aa)
bb = se.send(6)#6,赋值给b,之后执行print,返回a+b给bb
print(bb)
cc = se.send(7)#7,赋值给c,之后执行print,无yield了,所以返回StopIteration给cc
print(cc)

# 结果:
# --> start
# 5
# --> receive  5 6
# 11
# --> receive  5 6 7
# Traceback (most recent call last):
#   File "D:/Python/Python项目/基础学习/7-15/v02.py", line 13, in <module>
#     cc = se.send(7)
# StopIteration

**v03**
class DemoException(Exception):
    """
    custom exception
    """
    pass

def handle_exception():
    print('-> start')

    while True:
        try:
            x = yield
        except DemoException:
            print('-> run demo exception')
        else:
            print('-> recived x:', x)

    raise RuntimeError('this line should never run')

he = handle_exception()
next(he)
he.send(10) # recived x: 10
he.send(20) # recived x: 20

he.throw(DemoException) # run demo exception

he.send(40) # recived x: 40
he.close()
**v04**
class DemoException(Exception):
    """
    custom exception
    """
    pass

def handle_exception():
    print('-> start')

    while True:
        try:
            x = yield
        except DemoException:
            print('-> run demo exception')
        else:
            print('-> recived x:', x)


he = handle_exception()
next(he)
he.send(10) # recived x: 10
he.send(20) # recived x: 20


try:
    he.send(40) # recived x: 40
    he.close()
    he.send(50) # recived x: 40
    he.close()
except Exception as e:
    print(str(e))
    print(e.value)

**v05**
def gen():
    for c in 'AB':
        yield c
# list直接用生成器作为参数
print(list(gen()))

def gen_new():
    yield from 'AB'

print(list(gen_new()))

#结果:
# ['A', 'B']
# ['A', 'B']
**v06**
# 案例v04, 委派生成器
from collections import namedtuple

'''
解释:
1. 外层 for 循环每次迭代会新建一个 grouper 实例,赋值给 coroutine 变量; grouper 是委派生成器。
2. 调用 next(coroutine),预激委派生成器 grouper,此时进入 while True 循环,调用子生成器 averager 后,在 yield from 表达式处暂停。
3. 内层 for 循环调用 coroutine.send(value),直接把值传给子生成器 averager。同时,当前的 grouper 实例(coroutine)在 yield from 表达式处暂停。
4. 内层循环结束后, grouper 实例依旧在 yield from 表达式处暂停,因此, grouper函数定义体中为 results[key] 赋值的语句还没有执行。
5. coroutine.send(None) 终止 averager 子生成器,子生成器抛出 StopIteration 异常并将返回的数据包含在异常对象的value中,yield from 可以直接抓取 StopItration 异常并将异常对象的 value 赋值给 results[key]
'''
ResClass = namedtuple('Res', 'count average')

# 子生成器
def averager():
    total = 0.0
    count = 0
    average = None

    while True:
        term = yield
        # None是哨兵值
        if term is None:
            break
        total += term
        count += 1
        average = total / count

    return ResClass(count, average)

# 委派生成器
def grouper(storages, key):
    while True:
        # 获取averager()返回的值
        storages[key] = yield from averager()

# 客户端代码
def client():
    process_data = {
        'boys_2': [39.0, 40.8, 43.2, 40.8, 43.1, 38.6, 41.4, 40.6, 36.3],
        'boys_1': [1.38, 1.5, 1.32, 1.25, 1.37, 1.48, 1.25, 1.49, 1.46]
    }
    storages = {}
    for k, v in process_data.items():
        # 获得协程
        coroutine = grouper(storages, k)

        # 预激协程
        next(coroutine)

        # 发送数据到协程
        for dt in v:
            coroutine.send(dt)

        # 终止协程
        coroutine.send(None)
    print(storages)

# run
client()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值