• Python协程函数


    1 协程函数

    1.1 协程函数理解

    协程函数就是使用了yield表达式形式的生成器

    def eater(name):
        print("%s eat food" %name)
        while True:
            food = yield
        print("done")
    
    g = eater("gangdan")
    print(g)
    

    结果:
    generator object eater at 0x00000000028DC048
    这里就证明了g现在就是生成器函数

    1. 2 协程函数赋值过程

    用的是yield的表达式形式

    要先运行next(),让函数初始化并停在yield,相当于初始化函数,然后再send() ,send会给yield传一个值
    ** next()和send() 都是让函数在上次暂停的位置继续运行,

    next是让函数初始化

    send在触发下一次代码的执行时,会给yield赋值
    **

    def eater(name):
        print('%s start to eat food' %name)
        food_list=[]
        while True:
            food=yield food_list
            print('%s get %s ,to start eat' %(name,food))
            food_list.append(food)
    
    
    e=eater('钢蛋')  # wrapper('')
    # print(e)
    print(next(e))     # 现在是运行函数,让函数初始化
    print(e.send('包子'))  #
    print(e.send('韭菜馅包子'))
    print(e.send('大蒜包子'))
    

    这里的关键是:
    要先运行next()函数

    用装饰器函数把next()函数先运行一次:

    def start(func):
        def wrapper(*args,**kwargs):
            res=func(*args,**kwargs)  # next()
            next(res)     # 这是关键
            return  res
        return wrapper
    
    @start   # e = start(e)
    def eater(name):
        print('%s start to eat food' %name)
        food_list=[]
        while True:
            food=yield food_list
            print('%s get %s ,to start eat' %(name,food))
            food_list.append(food)
    
    
    e=eater('钢蛋')  # wrapper('钢蛋')  
    
    print(e.send('包子'))
    print(e.send('韭菜馅包子'))
    print(e.send('大蒜包子'))
    

    在@start # e = start(e) 后面写上,运行start函数,start函数返回wrapper

    1.3 协程函数使用装饰器初始化

    这里主要是为了防止忘记初始化next操作,在装饰器中添加

    def init(func):
        def wrapper(*args,**kwargs):
            res = func(*args,**kwargs)
            next(res)     #  在这里执行next
            return res
        return wrapper
    
    @init            # eater=init(rater)
    def eater(name):
        print("%s eat food" %name)
        food_list=[]
        while True:
            food = yield food_list
            print("%s star to eat %s" %(name,food))
            food_list.append(food)
        print("done")
    
    g = eater("gangdan")
    
    # 这里就不需要next
    print(g.send("1"))
    print(g.send("2"))
    print(g.send("3"))
    print(g.send("4"))
    

    结果:
    gangdan eat food
    gangdan star to eat 1
    ['1']
    gangdan star to eat 2
    ['1', '2']
    gangdan star to eat 3
    ['1', '2', '3']
    gangdan star to eat 4
    ['1', '2', '3', '4']

    只要用到装饰器函数,马上写装饰器函数,写@init马上想到**  eater=init(eater)   **,先执行装饰器函数。
    
    **关键是**next(res),这里是是对生成器进行初始化。这里就会只执行一次,执行完后后面运行的都是e.send()
    
    
    
    ### 1.2 协程函数的应用 ###
    
    过滤一个文件下的子文件、字文件夹的内容中的相应的内容,在Linux中的命令就是 *grep -rl 'python'  /etc*
    
    使用了Python的包os 里面的walk(),能够把参数中的路径下的文件夹打开并返回一个元组
    ```python
    >>> import os
    >>> os.walk('D:	est')        
    generator object walk at 0x0000000002ADB3B8
    
    >>> os.walk('D:\test')        # 以后使用这种路径方式,win下
    >>> os.walk(r'D:	est')       # 使用r 是让字符串中的符号没有特殊意义,针对的是转义
    
    

    出现错误,是因为路径的原因,但是在不同的机器上有的是可以的

    >>> g=os.walk('D:	est')
    >>> next(g)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    StopIteration
    

    以后推荐是用

    >>> g=os.walk('D:\test')
    >>> next(g)
    ('D:\test', ['a', 'b'], ['test.txt'])
    

    返回的是一个元组第一个元素是文件的路径,第二个是文件夹,第三个是该路径下的文件

    1.2.1 程序流程

    1. 找文件路径 --os.walk
    2. 然后打开文件 --open
    3. 读取文件的每一行内容 -- for line in f
    4. 过滤一行内容中是否有Python if 'python' in line
    5. 打印包含Python的文件路径

    程序是从上往下执行的,1产生的路径作为参数给2,2产生的给3...

    上面产生的结果是下面的输入参数

    1 找文件的路径

    g是一个生成器,就能够用next()执行,每次next就是运行一次,这里的运行结果是依次打开文件的路径

    >>> g=os.walk('D:\test')
    >>> next(g)
    ('D:\test', ['a', 'b'], ['test.txt'])
    >>> next(g)
    ('D:\test\a', ['a1'], ['a.txt'])
    >>> next(g)
    ('D:\test\a\a1', [], ['a1.txt'])
    >>> next(g)
    ('D:\test\b', ['b1'], ['b.txt'])
    >>> next(g)
    ('D:\test\b\b1', [], ['b1.txt'])
    

    我们在打开文件的时候需要找到文件的绝对路径,现在可以通过字符串拼接的方法把第一部分和第三部分进行拼接

    用循环打开:

    import os
    # def serach():
    g = os.walk('D:\test')
    for i in g:
        print(i)
    

    结果:
    ('D: est', ['a', 'b'], ['test.txt'])
    ('D: esta', ['a1'], ['a.txt'])
    ('D: estaa1', [], ['a1.txt'])
    ('D: est', ['b1'], ['b.txt'])
    ('D: est1', [], ['b1.txt'])

    将查询出来的文件和路径进行拼接,拼接成绝对路径

    import os
    # def serach():
    g = os.walk('D:\test')
    for i in g:
        # print(i)
        for j in i[-1]: # 对最后一个元素进行遍历,这些都是文件
            file_path= '%s\%s' %(i[0],j)
            print(file_path)
    

    结果:
    D: est est.txt
    D: estaa.txt
    D: estaa1a1.txt
    D: est.txt
    D: est11.txt

    这样就把文件的所有的绝对路径找出来了

    用函数实现:

    def search():
        while True:
            file_name = yield   # 通过white循环能够循环接收
            g = os.walk(file_name)   # 这里就换成了参数
            for i in g:
                for j in i[-1]: # 对最后一个元素进行遍历,这些都是文件
                    file_path= '%s\%s' %(i[0],j)
                    print(file_path)
    
    g=search()  # g就是生成器函数
    next(g)   # 初始化
    g.send('D:\test') # 通过send传递的是路径
    

    2 然后打开文件

    写程序中,在这里遇到的问题是 with open(file_path) as f: AttributeError: enter,不明白是为什么,然后想到open可能是系统已经用了的,所以修改名字后执行成功。

    @init   # 初始化生成器
    def opener(target):
        "打开文件,操作句柄"
        while True:
            file_path=yield  #  接收search传递的路径
            with open(file_path) as f:
                target.send((file_path,f)) # send多个用元组的方式,为了把文件的路径传递下去
    

    3 读取文件的每一行内容

    @init
    def cat(target):
        while True:
            file_path,f=yield
            for line in f:
                target.send((file_path,line)) # 同时传递文件路径和每一行的内容
    

    4 过滤一行内容中是否有

    @init
    def grep(pattern,target):  # patter是过滤的参数
        while True:
            file_path,line=yield
            if pattern in line:
                target.send(file_path)   # 传递有相应内容的文件路径
    
    

    5 打印包含Python的文件路径

    @init
    def printer():
        while True:
            file_path=yield
            print(file_path)
    

    上面的是函数的定义阶段,下面是函数的执行阶段:

    g=search(opener(cat(grep('python',printer()))))
    g.send('D:\test')
    

    target这个生成器:
    opener(cat(grep('python',printer())))

    对此的理解:
    关于target还是有个点没有想明白,是target的传递的情况,我知道是从下面往上传递的。不明白的中怎么会这样接收,它的起始点在哪里

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

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

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

  • 相关阅读:
    如何自己手写一个热加载(转)
    阻塞I/O、非阻塞I/O和I/O多路复用、怎样理解阻塞非阻塞与同步异步的区别?
    Java NIO浅析 转至 美团技术团队
    mysql在线修改表结构大数据表的风险与解决办法归纳(转)
    MySQL性能优化
    Tomcat Connector(BIO, NIO, APR)三种运行模式(转)
    redis 单线程的理解
    Spring 中的bean 是线程安全的吗?
    Spring 自定义注解,结合AOP,配置简单日志注解 (转)
    redis 分布式锁
  • 原文地址:https://www.cnblogs.com/Python666/p/6702422.html
Copyright © 2020-2023  润新知