在使用装饰器时,在碰到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的功能。
使用面向过程的方式,对具体的细节进行定义:
- 第一步:找到文件的绝对路径
- 第二步:打开文件
- 第三步:循环读出每一行内容
- 第四步:过滤
- 第五步:打印该行的属于的文件名
文件的绝对路径可以使用 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')











网友评论