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()
|
现在就可以步入正题了,那就是使用 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:
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.
参考文档:
http://www.ibm.com/developerworks/cn/opensource/os-cn-python-yield/
python manual