美文网首页
Python协程函数

Python协程函数

作者: 断尾壁虎V | 来源:发表于2017-12-01 16:29 被阅读0次

在使用装饰器时,在碰到yield时,停止执行,并返回yield的返回值。协程函数可以对yield的返回值进行赋值, 装饰器使用send()函数。

def test(name):
    print('%s welcome' %name)
    while True:
        age=yield
        print('%s is %s' %(name,age))

t=test('andy')
# 初始化,必须先进行初始化,否则会报错
next(t)
# 使用send() 给yield传值,yield将得到的值赋值给age
print(t.send('22'))
print('=========')
print(t.send('33'))

输出结果:
andy welcome
andy is 22
None
=========
andy is 33
None

在使用装饰器对yield复制前。需要使用next() 方法进行初始化,初始化的目的是给他传一个None值,同理,也可以使用send(None)的方式进行初始化,如果没有初始化这步,会有一个如下的报错:

TypeError: can't send non-None value to a just-started generator

当一个next()执行完毕之后会在yield处停止,并返回yield的值,默认为None,也可以指定固定的返回值。

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

在执行协程函数的时候,必须要有一部初始化的过程,我们可以使用装饰器来增加这项功能。

def init(func):
    def wrapper(*args,**kwargs):
        g=func(*args,**kwargs)
        next(g)      # 在装饰器中添加next() 方法,函数调用方式不变
        return g
    return wrapper

@init
def test(name):
    print('%s welcome' %name)
    city_list=[]
    while True:
        city=yield city_list
        city_list.append(city)
        print('%s gone to %s' %(name,city))

def aa():
    t=test('andy')
    print(t.send('BJ'))
    print('=========')
    print(t.send('SH'))
    # t.send('1')

aa()

整个装饰器增加了next()初始化装饰器的功能,在其他对象调用此函数时就不必初始化,直接调用。

面向过程编程

面向过程是按照解决问题的步骤,基于面向过程去设计程序 ,就如一条工业流水线。是一种机械的思维方式。

  • 优点:程序结构清晰,可以把复杂的问题简单化,流程化
  • 缺点:可扩展性差,一条流水线只是用来解决一个问题。
  • 应用场景:Linux内核,git,httpd, shell脚本。

使用面向过程过程的方式,编写一个实现类似grep -rl error /dir的功能。
使用面向过程的方式,对具体的细节进行定义:

  1. 第一步:找到文件的绝对路径
  2. 第二步:打开文件
  3. 第三步:循环读出每一行内容
  4. 第四步:过滤
  5. 第五步:打印该行的属于的文件名

文件的绝对路径可以使用 g=os.walk(r'D:\python36-project\test\file')的方式可以获取文件的路径和列表,这里的生成的对象g是一个迭代器:

import os
g=os.walk(r'D:\python36-project\test\file')
print(next(g))

输出的是一个元组,里面有多个列表,第一项是路径,第二项是目录列表,第三项是文件列表:
('D:\python36-project\test\file', [], ['111.jpg', '222.jpg', '3.jpg', 'a.txt', 'file_op.py', 'function.py', 'iter.py'])

第一步:找到文件的绝对路径:

import os

def init(func):
    def wrapper(*args,**kwargs):
        g=func(*args,**kwargs)
        next(g)
        return g
    return wrapper
@init
def search():
    while True:
        filepath=yield
        g=os.walk(filepath)
        for paradir,_,files in g:
            for file in files:
                abspath=r'%s\%s' %(paradir,file)
                print(abspath)
search().send(r'D:\python36-project\test\file')

第二步: 打开文件:

import os

def init(func):
    def wrapper(*args,**kwargs):
        g=func(*args,**kwargs)
        next(g)
        return g
    return wrapper

# 第一步:找到文件的绝对路径
@init
def search(target):
    while True:
        filepath=yield
        g=os.walk(filepath)
        for paradir,_,files in g:
            for file in files:
                abspath=r'%s\%s' %(paradir,file)
                target.send(abspath)
# 第二步: 打开文件
@init
def opener():
    while True:
        abspath=yield
        with open(abspath) as f:
            print(f)

search(opener()).send(r'D:\python36-project\test\file')

打开文件是,使用search()中传递的值,利用装饰器初始化,将search()获取的值传递给opener()

第三步,读取文件:

import os
def init(func):
    def wrapper(*args,**kwargs):
        g=func(*args,**kwargs)
        next(g)
        return g
    return wrapper
@init     查找文件
def search(target):
    while True:
        filepath=yield
        g=os.walk(filepath)
        for paradir,_,files in g:
            for file in files:
                abspath=r'%s\%s' %(paradir,file)
                target.send(abspath)
@init       # 打开文件
def opener(target):
    while True:
        abspath=yield
        with open(abspath) as f:
            target.send(f)
@init        # 读取文件
def cat():
    while True:
        f=yield
        for line in f:
            print(line)
search(opener(cat())).send(r'D:\python36-project\test\file') # 调用传参

第四步:过滤, 使用类似的yield传参数的方式,这里可以打印出匹配的行:

import os

def init(func):
    def wrapper(*args,**kwargs):
        g=func(*args,**kwargs)
        next(g)
        return g
    return wrapper
@init
def search(target):
    while True:
        filepath=yield
        g=os.walk(filepath)
        for paradir,_,files in g:
            for file in files:
                abspath=r'%s\%s' %(paradir,file)
                target.send(abspath)

@init
def opener(target):
    while True:
        abspath=yield
        with open(abspath) as f:
            target.send(f)

@init
def cat(filecon):
    while True:
        f=yield
        for line in f:
            filecon.send(line)


@init
def greps(context):
    while True:
        line=yield
        if context in line:
            print(line)

search(opener(cat(greps('error')))).send(r'D:\python36-project\test\file\aaa')

第五步:打印出文件匹配的行和文件名:

import os

def init(func):
    def wrapper(*args,**kwargs):
        g=func(*args,**kwargs)
        next(g)
        return g
    return wrapper
@init
def search(target):
    while True:
        filepath=yield
        g=os.walk(filepath)
        for paradir,_,files in g:
            for file in files:
                abspath=r'%s\%s' %(paradir,file)
                target.send(abspath)

@init
def opener(target):
    while True:
        abspath=yield
        with open(abspath) as f:
            target.send((abspath,f))  # 使用元组传递两个参数,文件名和文件内容

@init
def cat(filecon):
    while True:
        abspath,f=yield
        for line in f:
            filecon.send((abspath,line))  # 使用元组传递文件名,和每行内容


@init
def greps(context):
    while True:
        abspath,line=yield
        if context in line:
            print(line,abspath)  # 打印每行内容和改行所在的文件

g=search(opener(cat(greps('error'))))
g.send(r'D:\python36-project\test\file\aaa')

上面的代码能实现这一功能,但是如果是多行匹配的文件荣会出现多个重复的路径,如果只显示匹配的文件名称,不显示匹配行的内容就需要去掉重复的文件名。
修改为如下代码:

import os

def init(func):
    def wrapper(*args,**kwargs):
        g=func(*args,**kwargs)
        next(g)
        return g
    return wrapper
@init
def search(target):
    while True:
        filepath=yield
        g=os.walk(filepath)
        for paradir,_,files in g:
            for file in files:
                abspath=r'%s\%s' %(paradir,file)
                target.send(abspath)

@init
def opener(target):
    while True:
        abspath=yield
        with open(abspath) as f:
            target.send((abspath,f))

@init
def cat(filecon):
    while True:
        abspath,f=yield
        for line in f:
            res=filecon.send((abspath,line))  # 匹配文件后 res=True
            if res:break    # 如果res=True 跳出循环


@init
def greps(context):
    tag=False     # 没有匹配时不跳出循环
    while True:
        abspath,line=yield tag   # 返回修改的tag=True 结束循环
        tag=False     # 匹配上之后,在循环下一个文件时默认为False,继续查找写一个文件内容
        if context in line:
            print(abspath)
            tag=True           # 如果找到匹配的行,就便利下一个文件

g=search(opener(cat(greps('error'))))
g.send(r'D:\python36-project\test\file\aaa')

相关文章

  • Python异步: 定义、创建和运行协程(5)

    我们可以在我们的 Python 程序中定义协程,就像定义新的子例程(函数)一样。一旦定义,协程函数可用于创建协程对...

  • python异步协程(aiohttp,asyncio)

    python异步协程 环境:python3.7.0 协程 协程,英文叫做 Coroutine,又称微线程,纤程,协...

  • 2018-12-16 协程

    协程 又叫微线程,纤程python 对协程的实现是通过generator实现的 生成器-含有yield 有函数-生...

  • Python协程函数

    在使用装饰器时,在碰到yield时,停止执行,并返回yield的返回值。协程函数可以对yield的返回值进行赋值,...

  • async/await协程语法

    协程函数(异步函数)使用async关键词将其变成协程方法 执行协程 协程函数执行结束时会抛出一个StopItera...

  • 21. Go 协程

    21. Go 协程 Go 协程是什么? Go 协程是与其他函数或方法一起并发运行的函数或方法。Go 协程可以看作是...

  • asyncio + asyncio 异步编程实例

    协程用法 接下来,我们来了解下协程的实现,从 Python 3.4 开始,Python 中加入了协程的概念,但这个...

  • Python 协程

    仅供学习,转载请注明出处 协程 协程,又称微线程,纤程。英文名Coroutine。 协程是啥 协程是python个...

  • 协程

    协程是python中另外一种实现多任务的方式 协程就是:在一个线程中的某个函数可以在任何地方保存当前函数的一些临时...

  • 协程

    1.协程 协程,又称微线程,纤程。英文名Coroutine。 1.1 协程是什么 协程是python个中另外一种实...

网友评论

      本文标题:Python协程函数

      本文链接:https://www.haomeiwen.com/subject/wkaubxtx.html