• 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 里面为了方便写简单的生成器 提供一个方法 类似于列表推导

    用(方法 循环 条件)

  • 相关阅读:
    poj2976 Dropping tests (01分数规划)
    bzoj5281/luogu4377 Talent Show (01分数规划+背包dp)
    bzoj5280/luogu4376 MilkingOrder (二分答案+拓扑序)
    bzoj1492/luogu4027 货币兑换 (斜率优化+cdq分治)
    [模板]树状数组
    匿名函数 python
    yield解析你要知道的源自IBM
    stackoverflow yield 帖子
    pandas 生成器,生成大数据
    pd.contact,dataframe 拼接
  • 原文地址:https://www.cnblogs.com/nerdlerss/p/7066568.html
Copyright © 2020-2023  润新知