关于Python中的yield

原创 2016年08月29日 12:50:16

http://www.cnblogs.com/tqsummer/archive/2010/12/27/1917927.html


关于Python中的yield

在介绍yield前有必要先说明下Python中的迭代器(iterator)和生成器(constructor)。

一、迭代器(iterator)

在Python中,for循环可以用于Python中的任何类型,包括列表、元祖等等,实际上,for循环可用于任何“可迭代对象”,这其实就是迭代器

迭代器是一个实现了迭代器协议的对象,Python中的迭代器协议就是有next方法的对象会前进到下一结果,而在一系列结果的末尾是,则会引发StopIteration。任何这类的对象在Python中都可以用for循环或其他遍历工具迭代,迭代工具内部会在每次迭代时调用next方法,并且捕捉StopIteration异常来确定何时离开。

使用迭代器一个显而易见的好处就是:每次只从对象中读取一条数据,不会造成内存的过大开销。

比如要逐行读取一个文件的内容,利用readlines()方法,我们可以这么写:


1
2

for line in open("test.txt").readlines():
print line

这样虽然可以工作,但不是最好的方法。因为他实际上是把文件一次加载到内存中,然后逐行打印。当文件很大时,这个方法的内存开销就很大了。

利用file的迭代器,我们可以这样写:


1
2

for line in open("test.txt"):   #use file iterators
print line

这是最简单也是运行速度最快的写法,他并没显式的读取文件,而是利用迭代器每次读取下一行。

二、生成器(constructor)

生成器函数在Python中与迭代器协议的概念联系在一起。简而言之,包含yield语句的函数会被特地编译成生成器。当函数被调用时,他们返回一个生成器对象,这个对象支持迭代器接口。函数也许会有个return语句,但它的作用是用来yield产生值的。

不像一般的函数会生成值后退出,生成器函数在生成值后会自动挂起并暂停他们的执行和状态,他的本地变量将保存状态信息,这些信息在函数恢复时将再度有效


1
2
3
4
5
6
7
8

>>> def g(n):
... for i in range(n):
... yield i **2
...
>>> for i in g(5):
... print i,":",
...
0 : 1 : 4 : 9 : 16 :

要了解他的运行原理,我们来用next方法看看:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

>>> t = g(5)
>>> t.next()
0
>>> t.next()
1
>>> t.next()
4
>>> t.next()
9
>>> t.next()
16
>>> t.next()
Traceback (most recent call last):
File "", line 1, in <</span>module>
StopIteration

在运行完5次next之后,生成器抛出了一个StopIteration异常,迭代终止。
再来看一个yield的例子,用生成器生成一个Fibonacci数列:


1
2
3
4
5
6
7
8
9
10

def fab(max):
a,b = 0,1
while a <</span> max:
yield a
a, b = b, a+b
 
>>> for i in fab(20):
... print i,",",
...
0 , 1 , 1 , 2 , 3 , 5 , 8 , 13 ,

看到这里应该就能理解生成器那个很抽象的概念了吧~~

感觉跟递归很像。


下面我们用yield来读文件:

随便建一个文件类似

1

2

3

一般我们读文件可以这样读

def read(file):

        with open(file) as f:

                for line in f.readlines():

                        print line

if __name__ == '__main__':

read("inputFile.txt")

但其实readlines这样子一下全读进来了,占内存。

我们用yield读

def read(file):

        with open(file) as f:

                for line in f:

                        yield line.strip()



if __name__ == '__main__':

        reader = read("inputFile.txt")

        line = reader.next()

        while line:

                line = reader.next()

                print line


或者这样
def read(file):
        with open(file) as f:
                for line in f:
                        yield line.strip()


if __name__ == '__main__':
        reader = read("inputFile.txt")
        for line in reader:
                print line

十二、Python的yield用法与原理

翻了一篇workflow上关于yield的用法,翻的有点烂,在这里贻笑大方了,慢慢来,总是期待着一点一点的进步。 为了理解yield的机制,我们需要理解什么是生成器。在此之前先介绍迭代器iter...

python中yield与with的配合

最近在看openstack的代码的时候,发现了两个有趣的关键字,with和yield yield的作用是使所在的函数变成一个生成器,可以用next()函数来执行,并在遇到yield后中断,再次调用n...

浅析python中的yield机制

最近在看python中关于协程的部分,看到廖雪峰的官方网站中关于消费者和生产者那一部分有些困惑,于是自己研究了一下,有了以下了解: 代码:def consumer(): r = 'a' ...

新手学python(3):yield与序列化

1 Yield生成器        Yield是我在其他语言中没有见过的一个属性,算是python的一大特色,用好之后可以使代码更简洁。考虑一个简单的例子,文件的遍历。要遍历一个目录下的所有文件需要...

惰性求值和yield-Python

惰性求值惰性求值(Lazy evaluation)是在需要时才进行求值的计算方式。表达式不在它被绑定到变量之后就立即求值,而是在该值被取用的时候求值。除可以得到性能的提升(更小的内存占用)外,惰性计算...

关于Python生成器(Generator的yield、next、send)

习惯了C++和Java等强类型的语言,函数调用都是顺序执行的,返回之后栈清空,不留痕迹。初次遇到Python生成器,理解起来,真是破费周章。 关于Python生成器,大概需要关心的主要是yield...

Python yield 使用浅析(作者:廖雪峰)

初学 Python 的开发者经常会发现很多 Python 函数中用到了 yield 关键字,然而,带有 yield 的函数执行流程却和普通函数不一样,yield 到底用来做什么,为什么要设计 yiel...
  • Artprog
  • Artprog
  • 2016年08月25日 11:40
  • 767

python中yield深入理解

欢迎使用Markdown编辑器写博客yield关键字用来定义生成器(Generator),其具体功能是可以当return使用,从函数里返回一个值,不同之处是用yield返回之后,可以让函数从上回yie...

提高你的Python: 解释yield’和Generators(生成器)

在开始课程之前,我要求学生们填写一份调查表,这个调查表反映了它们对Python中一些概念的理解情况。一些话题("if/else控制流" 或者 "定义和使用函数")对于大多数学生是没有问题的。但是有一些...
  • cn_wk
  • cn_wk
  • 2016年05月04日 17:59
  • 688

利用 Python yield 创建协程将异步编程同步化

利用 Python yield 创建协程将异步编程同步化 Python 2015-09-07 08:40:34 发布 您的评价: 0.0 收藏 0收藏 在 Lua 和 Pyt...
  • a675311
  • a675311
  • 2016年11月14日 17:57
  • 361
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:关于Python中的yield
举报原因:
原因补充:

(最多只允许输入30个字)