通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。
在Python
中,这种一边循环一边计算的机制,称为生成器(Generator
)
创建生成器
1、将列表生成器的[]
改为()
就会创建一个generator
# 列表生成器,一次性全部生成
>>> L = [i*i for i in range(5)]
>>> print L
[0, 1, 4, 9, 16]
# 创建生成器
>>> g = (i*i for i in range(5))
>>> print g
<generator object <genexpr> at 0x7fbbdbd68b90>
# 使用next()方法一个个打印出来。
>>> g.next()
0
>>> g.next()
1
>>> g.next()
4
>>> g.next()
9
>>> g.next()
16
>>> g.next()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>>
注:generator
保存的是算法,每次调用next()
,就计算出下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration
的错误。
这种情况下,使用for
循环会更好,因为是可迭代的。
>>> g = (i*i for i in range(5))
>>> for i in g:
... print i
...
0
1
4
9
16
例:斐波那契数列,用函数实现,如下:
# 普通函数
>>> def fib(max):
... n,a,b = 0,0,1
... while n < max:
... print b
... a,b = b,a+b
... n += 1
...
>>> fib(6)
1
1
2
3
5
8
# 使用生成器
>>> def fib(max):
... n,a,b = 0,0,1
... while n < max:
... yield b
... a,b = b,a+b
... n += 1
...
>>> for i in fib(6):
... print i
...
1
1
2
3
5
8
2、使用yield
关键字,该函数就变为一个生成器。
generator
和函数的执行流程不一样。函数是顺序执行,遇到return
语句或者最后一行函数语句就返回。而变成generator
的函数,在每次调用next()
的时候执行,遇到yield
语句返回,再次执行时从上次返回的yield
语句处继续执行。
>>> def odd():
... print "step 1"
... yield 1
... print "step 2"
... yield 3
... print "step 3"
... yield 5
...
>>> o = odd()
>>> o.next()
step 1
1
>>> o.next()
step 2
3
>>> o.next()
step 3
5
>>> o.next()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration