一、yield工作原理
def consumer():
r = ''
while True:
n = yield r # 第2步:yield接收,n=None # 第4步:n=1 # 第6步:返回 r="200 OK"; 备注: "n"是收到生产者的数据(赋值给"n"),"r"是返回给生产者的数据.
if not n:
return
print('[消费者] Consuming %s...' % n) #第4步:打印 n=1
r = '200 OK' # 第5步:赋值
def produce(c):
# 注意:next(c) 和 c.send(None)是相等的
c.send(None) # 第1步. 唤醒consumer进入到yield
n = 0
while n < 5:
n = n + 1
print('[生产者] Producing %s...' % n)
r = c.send(n) # 第3步. 发送数据"1"给comsumer中的yield # 第7步.收到r="200 OK"
print('[生产者] Consumer return: %s' % r) # 打印r值
c.close()
c = consumer()
produce(c)
# yield有3个作用
# 1. 冻结
# 2. 返回数据
# 3. 接收数据
# yield工作过程
# 1. c.send(1)传值给yield,yield先赋值给n然后向下运行。
# 2. 通过while循环再次遇到yield后,则返回yield后面r的值。
二、迭代器
1. 有__iter__()方法的对象叫Iterable。 如:tuple list dict string set open(file)
2. 有__next__()和__iter__()方法的对象叫迭代器对象。 如:open(file)
3. 迭代器对象一定是可迭代对象, 而可迭代对象不一定是迭代器对象。
4. 有了迭代器我们可不依赖索引取值了。
#基于for循环,我们可以完全不再依赖索引去取值了
dic={'a':1,'b':2,'c':3}
for k in dic:
print(dic[k])
#for循环的工作原理
#1:执行in后对象的dic.__iter__()方法,得到一个迭代器对象iter_dic
#2: 执行next(iter_dic),将得到的值赋值给k,然后执行循环体代码
#3: 重复过程2,直到捕捉到异常StopIteration,结束循环
#优点:
- 提供一种统一的、不依赖于索引的迭代方式
- 惰性计算,节省内存
#缺点:
- 无法获取长度(只有在next完毕才知道到底有几个值)
- 一次性的,只能往后走,不能往前退
三、生成器
1. 只要函数内部包含有yield关键字,那么函数名()的到的结果就是生成器,并且不会执行函数内部代码
2. 生成器就是特殊的迭代器
例:
1、自定义函数模拟range(1,7,2)
2、模拟管道,实现功能:tail -f access.log | grep '404'
#题目一:
def my_range(start,stop,step=1):
while start < stop:
yield start
start+=step
#执行函数得到生成器,本质就是迭代器
obj=my_range(1,7,2) #1 3 5
print(next(obj))
print(next(obj))
print(next(obj))
print(next(obj)) #StopIteration
#应用于for循环
for i in my_range(1,7,2):
print(i)
#题目二
import time
def tail(filepath):
with open(filepath,'rb') as f:
f.seek(0,2)
while True:
line=f.readline()
if line:
yield line
else:
time.sleep(0.2)
def grep(pattern,lines):
for line in lines:
line=line.decode('utf-8')
if pattern in line:
yield line
for line in grep('404',tail('access.log')):
print(line,end='')
#测试
with open('access.log','a',encoding='utf-8') as f:
f.write('出错啦404
')
3、模拟吃饭
#yield关键字的另外一种使用形式:表达式形式的yield
def eater(name):
print('%s 准备开始吃饭啦' %name)
food_list=[]
while True:
food=yield food_list
print('%s 吃了 %s' % (name,food))
food_list.append(food)
g=eater('egon')
g.send(None) #对于表达式形式的yield,在使用时,第一次必须传None,g.send(None)等同于next(g)
g.send('蒸羊羔')
g.send('蒸鹿茸')
g.send('蒸熊掌')
g.send('烧素鸭')
g.close()
g.send('烧素鹅')
g.send('烧鹿尾')
4、通过装饰器初始化yield生成器函数
(1)、编写装饰器,实现初始化协程函数的功能
(2)、实现功能:grep -rl 'python' /etc
#题目一:
def init(func):
def wrapper(*args,**kwargs):
g=func(*args,**kwargs)
next(g)
return g
return wrapper
@init
def eater(name):
print('%s 准备开始吃饭啦' %name)
food_list=[]
while True:
food=yield food_list
print('%s 吃了 %s' % (name,food))
food_list.append(food)
g=eater('egon')
g.send('蒸羊羔')
#题目二:
#注意:target.send(...)在拿到target的返回值后才算执行结束
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 dirname,_,files in g:
for file in files:
abs_path=r'%s\%s' %(dirname,file)
target.send(abs_path)
@init
def opener(target):
while True:
abs_path=yield
with open(abs_path,'rb') as f:
target.send((f,abs_path))
@init
def cat(target):
while True:
f,abs_path=yield
for line in f:
res=target.send((line,abs_path))
if res:
break
@init
def grep(pattern,target):
tag=False
while True:
line,abs_path=yield tag
tag=False
if pattern.encode('utf-8') in line:
target.send(abs_path)
tag=True
@init
def printer():
while True:
abs_path=yield
print(abs_path)
g=search(opener(cat(grep('你好',printer()))))
# g.send(r'E:CMSaaadb')
g=search(opener(cat(grep('python',printer()))))
g.send(r'E:CMSaaadb')