python3之协程、迭代器、生成器

1、协程

-参考资料

         -http://python.jobbole.com/86481/

         -htttp://python.jobbloe.com/87310/

         -http://segmentfault.com/a/119000000781688

2、迭代器

-可迭代(Iterable):直接作用于for循环的变量

-迭代器(Iterator):不但可以作用于for循环,还可以被next调用

-list是典型的可迭代对象,但不是迭代器

#可迭代
I = [i for i in range(10)]
#I是可迭代的,但不是迭代器
for idx in I:
    print(idx)

#range是个迭代器
for i in range(5):
    print(i)

-通过isinstance判断是不是迭代器

#isinstance案例
#判断某个变量是否是一个实例

#判断是否可迭代
from collections.abc import Iterable
ll = [1,2,3,4,5]
print(isinstance(ll,Iterable))

from collections.abc import Iterator
print(isinstance(ll,Iterator))
运行:
True
Flase

-iterable和iterator可以转换

         -通过iter函数

#inter函数
from collections.abc import Iterable
from collections.abc import Iterator
s = 'I love wu'
print(isinstance(s,Iterable))
print(isinstance(s,Iterator))

s_iter = iter(s)
print(isinstance(s_iter,Iterable))
print(isinstance(s_iter,Iterator))

运行:
True
False
True
True

3、生成器

-generator:一边循环一边计算下一个元素的机制/算法

-需要满足三个条件
         -每次调用都生产出for循环需要的下一个元素或者

         -如果达到最后一个后,爆出StopIteration异常

         -可以被next函数调用

-如何生成一个生成器

        -直接使用

#直接使用生成器
L = [x*x for x in range(5)]#放在中括号中是列表生成器
g = (x*x for x in range(5))#放在小括号中就是生成器

print(type(L))
print(type(g))
运行:
<class 'list'>
<class 'generator'>

        -如果函数中包含yield,则这个函数就叫生成器

        -next调用函数,遇到yield返回

#生成器案例
#在函数odd中,yield负责返回
def odd():
    print("Step 1")
    yield 1
    print("Step 2")
    yield 2
    print("Step 3")
    yield 3
print(odd())

#想使用生成器用next函数,next执行下一步把内容返回到two里
g = odd()
#one = next(odd())
one = next(g)
print(one)

two = next(g)
print(two)

#for循环调用生成器
def fib(max):
    n,a,b = 0,0,1
    while n < max:
        print(b)
        a,b = b,a+b
        n += 1
    return 'done'
fib(5)

#斐波那契数列生成器写法
def fib(max):
    n,a,b = 0,0,1
    while n < max:
        yield b
        a,b = b,a+b
        n += 1
    #需要注意,爆出异常时的返回值是return的返回值
    return 'done'
'''
生成器的典型用法是在for中使用
比较常用的典型生成器是range
g = fib(10)
for i in ge:
    print (i)
'''
g = fib(5)
for i in range(6):
    rst = next(g)
    print(rst)
运行:
<generator object odd at 0x0000024F16981E58>
Step 1
1
Step 2
2
1
1
2
3
5
1
1
2
3
5
Traceback (most recent call last):
  File "D:/Python37/cources/统一包管理/线程/01.py", line 41, in <module>
    rst = next(g)
StopIteration: done

4、协程

-可用yield实现,实现的协程比较好的包有asyncio,tornado,gevent

-定义:协程 是为非抢占式多任务产生子程序的计算机程序组件,协程允许不同入口点在不同位置暂停或开始执行程序

-从技术角度讲,协程就是一个你可以暂停执行的函数,或者干脆把协程理解成生成器

-协程的实现
        -yield返回

        -send调用

#协程代码案例
def simple_coroutine():
    print('-> start')
    #把发的“消息”赋给x
    x = yield
    print("-> recived",x)

#主线程,生成一个协程
sc = simple_coroutine()
print(1111)
#可以使用sc.send(None),效果一样
next(sc)#育激

print(2222)
sc.send("消息")
运行:
1111
-> start
2222
-> recived 消息

-协程的四个状态

        -inspect.getgenratorstate(...)函数确定,该函数会返回下述字符串中的一个
        -GEN_CREATED:等待开始执行

        -GEN_RUNNING:解释器正在执行

        -GEN_SUSPENED:在yield表达式处暂停

        -next预激(prime)

#协程的状态
def simple_coroutine(a):
    print('-> start')

    b = yield a
    print("-> recived",a,b)

    c = yield a+b
    print("->recived",a,b,c)

#runc
sc = simple_coroutine(5)

aa = next(sc)
print(aa)
bb = sc.send(6) #5,6
print(bb)
cc = sc.send(7) #5,6,7
print(cc)
运行:
-> start
5
-> recived 5 6
11
->recived 5 6 7

-协程终止

        -协程中未处理的异常会向上冒泡,传给next函数或send方法的调用方法(即触发协程的对象)

        -终止协程的一种方式:发送某个哨符值,让协程退出,内置的None和Ellipsis等常量经常用作哨符值==

-yield from

        -调用协程为了得到返回值,协程必须正常终止

        -生成器正常终止会发出StopIteration异常,异常对象的value属性保存返回值

        -yield from从内部捕获StopIteration异常

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']

-委派生成器

        -包含yield from表达式的生成器函数

        -委派生成器在yield from表达式处暂停,调用方可以直接把数据发给自生成器

        -子生成器在把产出的值发给调用方

        -子生成器在最后,解释器会抛出StopIteration,并且把返回值附加到异常对象上

#委派生成器
from collections import namedtuple
'''
1、外层for循环每次迭代会新建一个grouper实例,赋值给coroutine变量:grouper是委派生成器
2、调用next(coroutine),预激委派生成器grouper,此时进入while True循环,调用了子生成器average
3、内层for循环调用coroutine.send(value),直接把值传给子生成器averager,同时,当前的grouper
4、内层循环结束后,grouper实例依旧在yield from表达式处暂停,因此,grouper函数定义体中
5、coroutine.send(None)终止averager子生成器,子生成器抛出StopIteration异常并将返回的数值
'''
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,45.3,34.2,78.2,12.3],
        'boys_1':[1.2,3.4,6.4,67.2,3.6]
    }
    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()
运行:
{'boys_2': Res(count=5, average=41.8)}
{'boys_2': Res(count=5, average=41.8), 'boys_1': Res(count=5, average=16.36)}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值