python-高级编程-02

【yield 详解 协同程序 生成器表达式】

1》 yield

def res ():
    for i in range(10):
        x = yield i
r = res() print r.next() print r.next() print r.next()

我们来详细的分析下这个程序的执行

r =res() 我们知道 res方法里面有yield关键字 那么这个方法就被认为是一个 generator 

那么 yield i 和 x = yield i  的功能上面的区别的就是 x = yield i 可以通过 send 修改表达式的值

yield i 可以理解加了挂起之后的return 

而 x = yileld i 这个表达式 

 则能够挂机的return + 能够在外部修改返回值

 

def res ():
    for i in range(10):
        yield i
        print '[1]',i
        yield i + 1
        print '[2]',i

r = res()
print r.next()
print r.next()

如果一个方法里面有两个yield 那么实际上是 这个方法会挂起两次 一次next 只能解除一次挂起

 

def psychologist():
print 'Please tell me your problems'
while 1:
res=(yield 3)
if res is not None:
if res.endswith('?'):
print ("Don't ask you self too much questions")
elif 'good' in res:
print "A that's good .go on "
elif 'bad' in res:
print "Don't be so negative"
else :
print 'res is None'

free = psychologist()
print '[0]',free.next()
print '[1]',free.next()
print '[2]',free.send("I feel bad")
print '[3]',free.send("Are you OK?")
print '[4]',free.send("I'm a good boy")

然后我们再来看这个代码 就简答很多了

res = yield 3

这里 执行next 或者send 的返回值都是 3 这个是不变的

而 res的值 会随着send 的变化而变化

这里我们可以吧next 看做 send(None)

第一次执行next() 会挂起在 yeild 哪里 所有 输出会是 : [0] 3

第二次执行 next() 就相当于 send(None)此时res = None 则会输出 :[1]  res is None 3

最终的全部输出

[0] 3
[1] res is None
3
[2] Don't be so negative
3
[3] Don't ask you self too much questions
3
[4] A that's good .go on 
3

 然后  和send 相匹配的函数还有两个  

    throw :允许客户端代码传入要抛出的任何类型 的异常

    close:跟throw 类似 但是只会抛出一个特定的异常 GeneratorExit 在这种情况下 生成器必须在抛出GeneratorExit 或Stopteration

可以在外部 让代码内部抛出异常

那么有了这三个特性我们就能通过生成器来编写协程

2》协程

定义:协同程序是可以挂起,恢复,并且有多个进入点的程序

import  multitask

def A1():
    for i in range(3):
        print 'A1',i
        yield i
        print 'in A'
def B1():
    for i in range(3):
        print 'B1',i
        yield i
        print 'in B'

multitask.add(A1())
multitask.add(B1())
multitask.run()

输出

A1 0
B1 0
in A
A1 1
in B
B1 1
in A
A1 2
in B
B1 2
in A
in B

  

multitask这个模块在这里实现了这一模式 一旦执行到yield这个关键字那么久挂起执行另一个函数的代码

我们可以自己写一个类似的程序
def A1():
    for i in range(3):
        print 'A1',i
        yield i
        print 'in A'
def B1():
    for i in range(3):
        print 'B1',i
        yield i
        print 'in B'

import  Queue
class my_task():
    def __init__(self):
        self._queue = Queue.Queue()

    def add(self,res):
        self._queue.put(res)

    def run(self):
        while not self._queue.empty():
            for i in xrange(self._queue.qsize()):
                try:
                    gen = self._queue.get()
                    gen.send(None)
                except StopIteration:
                    pass
                else:
                    self._queue.put(gen)

t = my_task()
t.add(A1())
t.add(B1())
t.run()

这段代码比较复杂了

我们来,了解下 queue 是先进先出的

这样就能很好的理解这个代码了

举个例子 小明和小强在玩游戏机 但是只有一个手柄 他们觉得达成协议 玩超级马里奥 然后一人玩一条命 一直到有一方通关

这里的手柄就是队列 ,通过队列实现这一效果

def a1():
    for x in range(4):
        print  x
        yield  x


def a2():
    for x in range(4,8):
        yield  x


threads=[]
threads.append(a1())
threads.append(a2())


def run(threads):
    while len(threads) != 0 :
        for i in threads:
            try:
                print i.next()
            except StopIteration:
                pass
            else:
                threads.append(i)

run(threads)

当然我们也可以通过其他方式来实现这一效果

3》生成器表达式

python 里面为了方便写简单的生成器 提供一个方法 类似于列表推导

用(方法 循环 条件)

 

posted @ 2017-06-22 18:30  nerdlerss  阅读(186)  评论(0编辑  收藏  举报