加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

再谈Python中的yield,return的区别

(2018-03-25 11:16:14)
标签:

python编程

迭代器和生成器

yield和return

分类: Python

初次学习Python,一定对yield的神奇功能感到好奇,又不好理解。下面用实际案例来说明yieldreturn的区别。

观点1

return是函数返回值,当执行到return,后续的代码不再执行;

yield是创建迭代器iteral,称之为生成器generator,让函数生成一个结果序列,而不仅仅是一个值,可以用for来遍历,有点事件触发的意思。可用现实的一种实物来理解:水车,先yield来装入数据、产出generator object、使用next()来释放;好比水车转动后,车轮上的水槽装入水,随着轮子转动,被转到下面的水槽就能将水送入水道中流入田里。好处是不用一次计算所以元素,而是用一次算一次,可以节省大量空间。

Exam-1

def  数数(n):

    while True:

        yield n     # yield n

        n += 1     # + =之间不能有空格,必须连起来

 

if __name__ ==  '__main__':

    ty = 数数(5)

    print(ty)

    for i in range(10):

        print(next(ty))

#上两句可以写成一句 print([next(ty) for I in range(10)])

 

Exam-2

def fib_yield():

    ""

    # generator fibonacci series: 1,1,2,3,5,8,13,....

    # enumerate(generator) include index and data (generator_object[index])

    #利用yield生产器,得到Fibonacci数列。

    ""

    a, b = 0, 1

    while True:

        yield a

        a, b = b, a+b

 

fib2 = fib_yield()

print([next(fib2)  for  _ in  range(10)])

 

如果要用send(),必须先用next()调用一次:

next(fib2)  #TypeError: can't send non-None value to a just-started generator

print([fib2.send(i)  for  i  in  range(10,20)])


 

观点2

return对应的是普通函数,函数可以多次进入,同时内部的状态信息会进行保存,执行完毕以后控制权移交给父函数,函数的上下文就此销毁;

yeild对应的是协程(Coroutine),长得像函数,实际不是函数,而是一个具有迭代功能的生成器。其他的地方几乎没有函数的影子,只是起了一个生成器的作用,所以你无法用执行语句的方法调用他,必须用next()send()函数进行调用。只要一个函数包含yield语句,就是具有迭代器功能的生成器。多用于异步或者递归。

next() 调用使生成器函数一直运行到下一条yield语句为止, 此时next()将返回值传递给yield,而且函数将暂时中止执行,再次调用next()时,函数将继续执行yield之后的语句。此过程将持续到函数返回为止。通常会使用一个for循环调用next()

 

什么是协程?

函数运行时要使用一组输入参数,但是,也可以将函数编写为一个任务,从而能处理发送给它的一系列输入,这类函数称为协程。

Exam-3

def matches(mtext):

    print("Looking for ", mtext)

    while True:

        try:

            line = (yield)   # 获得一行文本

            print(line)

            if mtext in line:

                print("%s to quit" % line)

        except StopIteration as es:

            print("StopeIteration :", es.argv)

        except TypeError as et:

            print("TypeError : ", et.args)

要使用这个函数,首先要调用它,向前执行第一条yield语句,然后使用send()函数给它发送数据。

    match = matches("quit")

    next(match)  # must use next(), otherwise raise TypeError: can't send non-None value to a just-started generator

    match.send("Hello World")

    match.send("python is cool")

    match.send("Yow!")

match.send("quit")

match.close()

观点3

从控制权来说,函数遇到return时,控制权交给主线程,然后没这个函数什么事了。如果遇到yield,控制权只是暂时交给主线程,函数继续在那等着。另外,函数里出现yield就自动变成生成器。

 

生成器是基于UNIX中处理管道、流或数据流编写程序的一种极其强大的方式。

下面的生成器用于在很多行中查找特定的子字符串:

Exam-4

def grep(lines, search):

    for line in lines:

        if search in line:

            yield search

     

更强大的例句,参见廖雪峰的官方微博:filter的强大用法

https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001431821084171d2e0f22e7cc24305ae03aa0214d0ef29000#0


0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有