zoukankan      html  css  js  c++  java
  • 协程函数

    首先要明确协程函数特点:yield变为表达式,可以通过g.send(value)传值,用send传值时协程函数需要初始化,也可以说是生成器函数的一种

    1、协程函数吃包子简洁案例

      下面代码中需要注意的是,yield的位置和作用,仔细看运行原理

    def eater(name):
        print('%s start to eat food' %name)#第一个print
        while True:
            food=yield
            print('%s get %s ,to start eat'%(name,food))#第二个print
        print('done')
    e=eater('钢蛋')#e是生成器#为什么在这里不会出现任何结果,因为在函数定义阶段Python解释器判断语法的时候就已经知道函数中有yield存在,知道这是一个生成器函数
    print(next(e))#next触发函数执行,执行第一个print后碰到yield是停止,但yield后面没有值,所以返回None
    # >>钢蛋 start to eat food
    # >>None
    print(next(e))#next触发函数执行,再上一个yield处开始运行,打印第二个print-->while true->又碰到yield后停止,但yield后面没有值,所以返回None
    # >>钢蛋 get None ,to start eat
    # >>None
    

      既然yield以表达式的形式出现了,我们就不得不想到赋值,那要赋值就得先传值,这里就会用到g.send(value),g指生成器,g.send(value)作用就和next(g)差不多一样,都是会触发函数进行运行一次,不一样的是,g.send(value)会把参数value传给yield再由yield赋值给等式另一边的对象,这个参数不会作为yield的返回值,send(value)可以传多个值,但是必须用元组形式例:g.send((value1,value2))

    def eater(name):
        print('%s start to eat food' %name)#第一个print
        while True:
            food=yield
            print('%s get %s ,to start eat'%(name,food))#第二个print
        print('done')
    e=eater('钢蛋')#e是生成器
    next(e)#next触发执行一次打印第一个print后碰到yield停止,这里没有打印
    # >>钢蛋 start to eat food
    e.send('包子')#send和next一样都会触发函数运行,碰到yield后停止得到一个返回值,不一样的地方就是send会把自己的参数交给当前暂停的yield,再由yield交给他赋值给的对象,这里是food,然后打印第二个print在经过whiletrue碰到yield停止,这里没有打印e.send('包子')的返回值
    # >>钢蛋 get 包子 ,to start eat
    print(e.send('包子'))#加上上面的运行结果后,还要返回None,因为yield后面依旧没有值,所以send执行完后他传入的参数也没了
    # >>钢蛋 get 包子 ,to start eat
    # >>None
    

      吃包子欢乐行,yield的返回值就是包子单,注意运行原理,始终围绕yield走

    def eater(name):
        print('%s start to eat food' %name)#第一个print
        food_list=[]
        while True:
            food=yield food_list
            print('%s get %s ,to start eat'%(name,food))#第二个print
            food_list.append(food)
        print('done')
    e=eater('钢蛋')#e是生成器
    print(next(e))
    print(e.send('包子'))
    print(e.send('韭菜包子'))
    print(e.send('榴莲包子'))
    
    #运行结果如下:
    # 钢蛋 start to eat food
    # []
    # 钢蛋 get 包子 ,to start eat
    # ['包子']
    # 钢蛋 get 韭菜包子 ,to start eat
    # ['包子', '韭菜包子']
    # 钢蛋 get 榴莲包子 ,to start eat
    # ['包子', '韭菜包子', '榴莲包子']
    

    2、我们每次给协程函数用g.send()传值时都需要一次初始化,可以用装饰器解决

    #利用装饰器帮助协程函数省去初始化步骤
    def next_free(func):
        def wrapper(*args,**kwargs):
            res = func(*args,**kwargs)
            next(res)
            return res     #res就是next()过一次的生成器,而且,这个装饰器是万能的
    @next_free #eater=next_free(eater)
    def eater(name):
        print('%s start to eat food' %name)#第一个print
        food_list=[]
        while True:
            food=yield food_list
            print('%s get %s ,to start eat'%(name,food))#第二个print
            food_list.append(food)
        print('done')
    g=eater('agon')
    

    3、面向过程的编程思想:流水线式的编程思想,在设计程序时,需要把整个流程设计出来

      优点:
      #1:体系结构更加清晰
      #2:简化程序的复杂度

      #缺点:
      #1:可扩展性极其的差,所以说面向过程的应用场景是:不需要经常变化的软件,如:linux内核,httpd,git等软件

    #grep -rl 'python' C:egon
    import os,time
    def init(func):
        def wrapper(*args,**kwargs):
            res=func(*args,**kwargs)
            next(res)
            return res
        return wrapper
    
    #找到一个绝对路径,往下一个阶段发一个
    @init
    def search(target):
        '找到文件的绝对路径'
        while True:
            dir_name=yield #dir_name='C:\egon'
            print('车间search开始生产产品:文件的绝对路径')
            time.sleep(2)
            g = os.walk(dir_name)
            for i in g:
                # print(i)
                for j in i[-1]:
                    file_path = '%s\%s' % (i[0], j)
                    target.send(file_path)
    
    @init
    def opener(target):
        '打开文件,获取文件句柄'
        while True:
            file_path=yield
            print('车间opener开始生产产品:文件句柄')
            time.sleep(2)
            with open(file_path) as f:
                target.send((file_path,f))
    
    @init
    def cat(target):
        '读取文件内容'
        while True:
            file_path,f=yield
            print('车间cat开始生产产品:文件的一行内容')
            time.sleep(2)
            for line in f:
                target.send((file_path,line))
    
    @init
    def grep(pattern,target):
        '过滤一行内容中有无python'
        while True:
            file_path,line=yield
            print('车间grep开始生产产品:包含python这一行内容的文件路径')
            time.sleep(0.2)
            if pattern in line:
                target.send(file_path)
    
    @init
    def printer():
        '打印文件路径'
        while True:
            file_path=yield
            print('车间printer开始生产产品:得到最终的产品')
            time.sleep(2)
            print(file_path)
    
    
    
    g=search(opener(cat(grep('python',printer()))))
    g.send('C:\egon')
    g.send('D:\dir1')
    g.send('E:\dir2')
    

      

      

  • 相关阅读:
    idea+maven使用
    MySQL数据库一个字段对应多个值得模糊查询
    什么时候用接口?什么时候用抽象类?
    线程的死锁和死锁解决的实际案例
    idea 实用插件
    linux查看日志报错
    mysql日期模糊查找的方法
    mysql 日期函数
    win10安装sonarqube
    docker中mysql数据库导出部分数据
  • 原文地址:https://www.cnblogs.com/wuyongqiang/p/6697009.html
Copyright © 2011-2022 走看看