yield的概念?
1.简单的斐波那契數列第一版:
|
|
缺点:直接在 fab 函数中用 print 打印数字会导致该函数可复用性较差,因为 fab 函数返回 None,其他函数无法获得该函数生成的数列。
2.简单的斐波那契數列第二版:
|
|
缺点:该函数在运行中占用的内存会随着参数 max 的增大而增大,如果要控制内存占用,最好不要用 List。
3.简单的斐波那契數列第三版:
根据range与xrange的思想设计:
|
|
缺点:代码远远没有第一版的 fab 函数来得简洁。
如果我们想要保持第一版 fab 函数的简洁性,同时又要获得 iterable 的效果,yield 就派上用场了。
|
|
yield 的作用就是把一个函数变成一个 generator,带有 yield 的函数不再是一个普通函数,Python 解释器会将其视为一个 generator,调用 fab(5) 不会执行 fab 函数,而是返回一个 iterable 对象!在 for 循环执行时,每次循环都会执行 fab 函数内部的代码,执行到 yield b 时,fab 函数就返回一个迭代值,下次迭代时,代码从 yield b 的下一条语句继续执行,而函数的本地变量看起来和上次中断执行前是完全一样的,于是函数继续执行,直到再次遇到 yield。
|
|
一个带有 yield 的函数就是一个 generator,它和普通函数不同,生成一个 generator 看起来像函数调用,但不会执行任何函数代码,直到对其调用 next()(在 for 循环中会自动调用 next())才开始执行。虽然执行流程仍按函数的流程执行,但每执行到一个 yield 语句就会中断,并返回一个迭代值,下次执行时从 yield 的下一个语句继续执行。看起来就好像一个函数在正常执行的过程中被 yield 中断了数次,每次中断都会通过 yield 返回当前的迭代值。比如在读取文件时候很好使用的。
|
|
Iterables,Generators,Yield?
当你创建了一个列表,你可以一个一个的读取它的每一项,这叫做iteration。所有你可以用在for...in...
语句中的都是可迭代的:比如lists,strings,files…因为这些可迭代的对象你可以随意的读取所以非常方便易用,但是你必须把它们的值放到内存里,当它们有很多值时就会消耗太多的内存.
|
|
生成器也是迭代器的一种,但是你只能迭代它们一次.原因很简单,因为它们不是全部存在内存里,它们只在要调用的时候在内存里生成。
|
|
生成器和迭代器的区别就是用()代替[],还有你不能用for i in mygenerator第二次调用生成器:首先计算0,然后会在内存里丢掉0去计算1,直到计算完4.
|
|
在这里这个例子好像没什么用,不过当你的函数要返回一个非常大的集合并且你希望只读一次的话,那么它就非常的方便了.要理解Yield你必须先理解当你调用函数的时候,函数里的代码并没有运行.函数仅仅返回生成器对象,这就是它最微妙的地方:-)然后呢,每当for语句迭代生成器的时候你的代码才会运转.一旦函数运行并没有碰到yeild语句就认为生成器已经为空了.原因有可能是循环结束或者没有满足if/else之类的.
|
|
yield的源码分析?
在解释生成器之前,需要讲解一下Python虚拟机的调用原理。
|
|
生成器的源码在Objects/genobject.c
|
|
send与next
|
|
从上面的代码中可以看到,send和next都是调用的同一函数gen_send_ex,区别在于是否带有参数。
|
|
参考:
http://www.ibm.com/developerworks/cn/opensource/os-cn-python-yield/