python之yield篇

本文深入探讨了Python中生成器的概念及其实现方法,包括使用yield表达式的具体细节。通过对斐波那契数列的多种实现方式的对比,文章详细讲解了如何利用生成器优化代码,提高内存效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://blog.chinaunix.net/uid-22334392-id-3480710.html


上一篇文章我们涉及到了函数,在最后一部分我们提到了yield 表达式,注意 yield产生的是表达式

为了便于理解我们从常见的斐波那契函数开始谈起,最容易让人想起的算法(至少对我而言是函数递归调用)

代码如下:


1
2
3
4
5
#common fab-style
def fab_ver1(n):
     if n = = 1 or n = = 0 :
         return 1
     return fab_ver1(n - 1 ) + fab_ver1(n - 2 )
上述实现的一个缺点是当数值很大的时候,递归调用栈会变的很深很深,因此不是太好,


那我们就继续改进吧,代码如下;


1
2
3
4
5
6
def fab( max ):
    n, a, b = 0 , 0 , 1
    while n < max :
        print b
        a, b = b, a + b
        n = n + 1


该实现的有点是避免了递归调用,但是一个一个缺点就是返回值不容易获得,解决方法也很简单,可以定义list,

通过list.append来保存所有的结果


1
2
3
4
5
6
7
8
def fab( max ):
    n, a, b = 0 , 0 , 1
     fab_list = []
    while n < max :
        fab_list.append(b)
        a, b = b, a + b
        n = n + 1
    return fab_list


这段代码同时存在的问题就是,当n很大的时候,保存结果的list将变得很庞大,虽然现在大多数的开发已不关心内存问题,但是这是

一个基本功的问题,我们可以略微的提高一下自己的水平哈


1
2
for i in range ( 10 ):
for i in xrange ( 10 ):
上述两行是不是看着很熟悉,可是你知道这二者的区别么?查文档如下:


range(...)
    range([start,] stop[, step]) -> list of integers
    
    Return a list containing an arithmetic progression of integers.

class xrange(object)
 |  xrange([start,] stop[, step]) -> xrange object
 |  
 |  Like range(), but instead of returning a list, returns an object that
 |  generates the numbers in the range on demand.  For looping, this is 
 |  slightly faster than range() and more memory efficient.

这下子你知道这二者的区别了吧?一个是返回list,另一个是返回一个xrange object,iteratorable object,也就是下一个

满足条件的object,且后者的速度明显要快于前者,更省内存--多快好省的事才会讨得领导欢心~~~~~~~····

那我们的函数能否也每一次都返回一个fab值呢?


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Fab( object ):
 
     def __init__( self , max ):
         self . max = max
         self .n, self .a, self .b = 0 , 0 , 1
 
     def __iter__( self ):
         return self
 
     def next ( self ):
         if self .n < self . max :
             r = self .b
             self .a, self .b = self .b, self .a + self .b
             self .n = self .n + 1
             return r
         raise StopIteration()
上述实现方式,在每次调用的时候都返回一个斐波那契值,但是一个简单的函数有必要写的这么负责么?况且python是以simple出名?


现在就可以步入正题了,那就是使用 yield 表达式


1
2
3
4
5
6
7
8
def fab():
     a,b = 0 , 1
     while 1 :
         a,b = b,a + b
         yield b
gf = fab()
for i in xrange ( 10 ):
     print '%4d' % gf. next (),


代码看起是不很simple,但是看起来是不是有点奇怪?

实现解释几个概念:  

gf=fab() 这里的gf不是你的’gf',而是generator的意思,注意这里虽然是定义成gf,但是它是一个generator,注意

后面没有了,只是generator,

fab() 才是 generator function 

fab()在调用的时候,并不执行,它的主要目的就是生成我们的GF,

那如何调用该函数呢?方法是通过NEXT 方法,注意next方法虽然能使函数执行,但是函数在遇到yield时变返回调用者,被调用者fab此时被

‘frozen‘(官方文档)= suspension(个人理解),此时被调用者状态会被保留下,直至下一次next调用或是抛出异常,也就是当调用者在此调用fab函数时,fab会resume,

即被被调用者函数能回复到上次程序suspension是的状态。调用者通过使用next方法来resume 被调用函数,被调用函数在遇到yield时,suspension自己。

还有一点需要强调的就是 yield 是表达式,那么表达式就是可以求值的,因此调用者此时就可以获取返回者,此例中为斐波那契值

在前面文章中,我们介绍了函数有很多属性,貌似generator 还有有点不一样,测试几个,结果如下:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def fab():
     """this is doc string """
     a,b = 0 , 1
     while 1 :
         a,b = b,a + b
         yield b
 
gf = fab()
g = fab()
print g,gf
for i in xrange ( 10 ):
     print '%4d' % gf. next (),
     
print gf.__doc__,gf.__name__
print gf.__class__,gf.__format__,
程序的输出:


<generator object fab at 0x01E38620> <generator object fab at 0x01E385F8>
   1    2    3    5    8   13   21   34   55   89 None fab
<type 'generator'> <built-in method __format__ of generator object at 0x01E385F8>

程序输出的第一行说明,每次调用generator function,都是返回 generator,但是二者的地址是不同的对象,这样在各自调用的时候就互不影响了~~~~~~~~~~~~~~~~·属性的部分由知道的比较详细的可以告诉我

PS:


Generator functions

A function or method which uses the yield statement (see section The yield statement) is called a generator function. Such a function, when called, always returns an iterator object which can be used to execute the body of the function: calling the iterator’s next()method will cause the function to execute until it provides a value using the yield statement. When the function executes a returnstatement or falls off the end, a StopIteration exception is raised and the iterator will have reached the end of the set of values to be returned.



generator A function which returns an iterator. It looks like a normal function except that it contains  yield  statements for producing a series a values usable in a for-loop or that can be retrieved one at a time with the  next()  function. Each  yield  temporarily suspends processing, remembering the location execution state (including local variables and pending try-statements). When the generator resumes, it picks-up where it left-off (in contrast to functions which start fresh on every invocation). 


参考文档:

http://www.ibm.com/developerworks/cn/opensource/os-cn-python-yield/


python manual


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值