python 生成器yield_python学习之生成器yield

本文详细介绍了Python中的生成器和yield关键字,包括它们的使用方式、工作原理以及在协程中的应用。通过实例解析了如何用生成器实现类似`tail -f | grep python`的功能,并展示了逆序和顺序使用生成器及协程的例子。
摘要由CSDN通过智能技术生成

python学习之生成器yield

yield的作用是使函数生成一个结果序列而不是一个值,任何使用yield的函数都称为生成器,调用生成器会创建一个对象,该对象通过连续调用next()或者__next__()方法生成结果序列

一般情况

>>> def count(n,m):

>>> print('这是一个循环外部测试')

>>> while n>0:

>>> print('这是一个循环内部测试')

>>> yield n,m

>>> n-=1

>>> c=count(5,2)

>>> c.__next__()

这是一个循环外部测试

这是一个循环内部测试

5,2

首先我定义了生成器,利用了yield关键词,但是注意,我没有像其它列子一样使用单个参数,yield的后面是两个参数,这里就是为了提醒,yield后面可以跟多个参数,他的后面参数表示要传给yield的这个关键词的参数,甚至可以用表达式,但是一定要用括号括起来,比如yield (n+3),这样的参数也可以

当初次调用count的时候,该函数什么也不做,因为他知道这是个yield的函数,所以也不会打印“这是一个外部循环测试"这段文字,但是,当调用__next__()之后,函数开始执行,执行到yield关键词,然后停止执行,函数的返回值就是要传给yield关键词的参数(其实用yield关键词相当于古时候的驿站,参数过来歇歇脚,然后继续上路,每遇到一次yield就要歇脚一次,调用一次__next__(),相当于开始赶路一次),就是如上图返回的5,2

当再次执行时,该函数从yield处开始执行,执行减一操作,然后继续循环,遇到yield停止

>>> c.__next__()

这是一个循环内部测试

4,2

>>> c.__next__()

这是一个内部循环测试

3,2

>>> c.__next__()

这是一个内部循环测试

2,2

下面一个python参考手册上的一个列子

利用pyhton实现linux上的tail -f |grep python这个命令

import time

def tail(f):

f.seek(0,2) #移动到EOF

while True:

line=f.readline()

if not line:

time.sleep(0.1) #尝试读取一个文件,如果没有,休眠并继续

continue

yield line

def grep(lines,searchtext):

for line in lines:

if searchtext in line:yield line

wwwlog=tail(open('access-log'))

pylines=grep(wwwlog,'python')

for line in pylines:

print(line)

协程与yield表达式

当yield表达式在右边时,这样的函数称为协程,它的执行是为了响应它的值

def receiver():

print('Ready to receive....')

while True:

n = (yield)

print('Got %s'%n)

上面的(yield)表达式接收该函数用send()发来的参数,赋值给n

>>> r=receiver() #形成一个协程,函数不执行

>>> r.__next__() #函数执行,直到遇到yield表达式

Ready to receive....

>>> r.send(1)

Got 1

>>> r.send('Hello')

Got Hello

>>>

这里的__next__()初始调用是必须的,这样协程才会挂起,直到对象利用send()方法传递一个值

如果想关闭协程,可以使用close()方法

>>> r.close()

>>>

注意:这里面n=(yield)表达式也可以将在yield后面加上返回值,如n=(yield result),这样该函数就有返回值

生成器与协程的用法

逆序使用生成器

import os

import fnmatch

def find_files(topdir,pattern):

for path ,dirname,filelist in os.walk(topdir):

for name in filelist:

if fnmatch.ffnmatch(name,pattern):

yield os.path.join(path,name)

import gzip,bz2

def opener(filenames):

for name in filenames:

if name.endswith(".gz"):f.gzip.open(name)

elif name.endswith(".bz2"):f=bz2.BZ2File(name)

else: f=open(name)

yield f

def cat(filelist):

for f in filelist:

for line in f:

yield line

def grep(pattern,lines):

for line in lines:

if pattern in line:

yield line

wwwlogs=find_files('www','access-log*')

files=opener(wwwlogs)

lines=cat(files)

pylines=grep('python',lines)

for line in pylines:

sys.stdout.write(line)

顺序使用协程

import os,fnmatch

#建立一个装饰器,将每次协程必须调用的next方法自动化

def coroutine(func):

def start(*args,**kwargs):

g=func(*args,**kwargs)

g.__next__()

return g

return start

@coroutine

def find_files(target):

while True:

topdir,pattern= (yield)

for path,dirname,filelist in os.walk(topdir):

for name in filelist:

if fnmatch.fnmatch(name,pattern):

target.send(os.path.join(path,name))

import gzip,bz2

@coroutine

def opener(target):

while True:

name=(yield)

if name.endswith('.gz'):f=gzip.open(name)

elif name.endswith('.bz2'):f=bz2.BZ2File(name)

else: f=open(name)

target.send(f)

@coroutine

def cat(target):

while True:

f=(yield)

for line in f:

targe.send(line)

@coroutine

def grep(pattern,target):

while True:

line =(yield)

if pattern in line:

target.send(line)

@coroutine

def printer():

while True:

line =(yield)

sys.stdout.write(line)

finder=find_files(opener(cat(grep('python',printer()))))

finder.send(('www','access-log*')) #发送的是一个整体,所以用括号

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值