首页 > 编程 > Python > 正文

Python中的生成器和yield详细介绍

2020-02-23 06:17:53
字体:
来源:转载
供稿:网友

列表推导与生成器表达式

当我们创建了一个列表的时候,就创建了一个可以迭代的对象:
代码如下:
>>> squares=[n*n for n in range(3)]
>>> for i in squares:
 print i
 
0
1
4

这种创建列表的操作很常见,称为列表推导。但是像列表这样的迭代器,比如str、file等,虽然用起来很方便,但有一点,它们是储存在内存中的,如果值很大,会很麻烦。

而生成器表达式不同,它执行的计算与列表包含相同,但会迭代的生成结果。它的语法与列表推导一样,只是要用小括号来代替中括号:
代码如下:
>>> squares=(n*n for n in range(3))
>>> for i in squares:
 print i
 
0
1
4

生成器表达式不会创建序列形式的对象,不会把所有的值都读取到内存中,而是会创建一个通过迭代并按照需求生成值的生成器对象(Generator)。

那么,还有没有其它方法来产生生成器呢?

例子:斐波那契数列

例如有个需求,要生成斐波那契数列的前10位,我们可以这样写:
代码如下:
def fib(n):
    result=[]
    a=1
    b=1
    result.append(a)
    for i in range(n-1):
        a,b=b,a+b
        result.append(a)
    return result
if __name__=='__main__':
    print fib(10)

数字很少时,函数运行良好,但数字很多时,问题就来了,显然生成一个几千几万长度的列表并不是一个很好的主意。

这样,需求就变成了:写一个可以生成可迭代对象的函数,或者说,不要让函数一次返回全部的值,而是一次返回一个值。

这好像与我们的常识相违背,当我们调用一个普通的Python函数时,一般是从函数的第一行代码开始执行,结束于return语句、异常或者函数结束(可以看作隐式的返回None):
代码如下:
def fib(n):
    a=1
    b=1
    for i in range(n-1):
        a,b=b,a+b
        return a
if __name__=='__main__':
    print fib(10)
>>>
1    #返回第一个值时就卡住了

函数一旦将控制权交还给调用者,就意味着全部结束。函数中做的所有工作以及保存在局部变量中的数据都将丢失。再次调用这个函数时,一切都将从头创建。函数只有一次返回结果的机会,因而必须一次返回所有的结果。通常我们都这么认为的。但是,如果它们并非如此呢?请看神奇的yield:

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表