首页IT科技python生成器作用(深入理解Python中的生成器)

python生成器作用(深入理解Python中的生成器)

时间2025-04-29 15:01:09分类IT科技浏览4778
导读:通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列...

通过列表生成式            ,我们可以直接创建一个列表            。但是                  ,受到内存限制       ,列表容量肯定是有限的                  。而且         ,创建一个包含100万个元素的列

表                  ,不仅占用很大的存储空间          ,如果我们仅仅需要访问前面几个元素      ,那后面绝大多数元素占用的空间都白白浪费了       。

所以                  ,如果列表元素可以按照某种算法推算出来             ,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list   ,从而节省大量的空间         。在Python中                  ,这种一边循环一边计算的机制                ,称为生成器(Generator)                  。

要创建一个generator,有很多种方法          。第一种方法很简单               ,只要把一个列表生成式的[]改成()                   ,就创建了一个generator:

>>>L=[x*xforxinrange(10)]>>>L [0,1,4,9,16,25,36,49,64,81]>>> g=(x*xforxinrange(10))>>>g <generatorobject<genexpr>at0x104feab40>

创建L和g的区别仅在于最外层的[]和()    ,L是一个list            ,而g是一个generator      。

我们可以直接打印出list的每一个元素                  ,但我们怎么打印出generator的每一个元素呢?

如果要一个一个打印出来       ,可以通过generator的next()方法:

>>>g.next() >>>g.next() 1 >>>g.next() 4 >>>g.next() 9 >>>g.next() 16 >>>g.next() 25 >>>g.next() 36 >>>g.next() 49 >>>g.next() 64 >>>g.next() 81 >>>g.next() Traceback(mostrecentcalllast): File"<stdin>",line1,in<module> StopIteration

我们讲过         ,generator保存的是算法                  ,每次调用next()          ,就计算出下一个元素的值      ,直到计算到最后一个元素                  ,没有更多的元素时             ,抛出StopIteration的错误                  。

当然   ,上面这种不断调用next()方法实在是太变态了                  ,正确的方法是使用for循环                ,因为generator也是可迭代对象:

>>>g=(x*xforxinrange(10)) >>>forning: ...printn ... 1 4 9 16 25 36 49 64 81

所以,我们创建了一个generator后               ,基本上永远不会调用next()方法                   ,而是通过for循环来迭代它             。

generator非常强大   。如果推算的算法比较复杂    ,用类似列表生成式的for循环无法实现的时候            ,还可以用函数来实现                  。

比如                  ,著名的斐波拉契数列(Fibonacci)       ,除第一个和第二个数外         ,任意一个数都可由前两个数相加得到:

1, 1, 2, 3, 5, 8, 13, 21, 34, ...

斐波拉契数列用列表生成式写不出来                  ,但是          ,用函数把它打印出来却很容易:

deffib(max): n,a,b=0,0,1 whilen<max:printb a,b=b,a+b n=n+1

上面的函数可以输出斐波那契数列的前N个数:

>>>fib(6) 1 1 2 3 5 8

仔细观察      ,可以看出                  ,fib函数实际上是定义了斐波拉契数列的推算规则             ,可以从第一个元素开始   ,推算出后续任意的元素                  ,这种逻辑其实非常类似generator                。

也就是说                ,上面的函数和generator仅一步之遥。要把fib函数变成generator,只需要把print b改为yield b就可以了:

deffib(max): n,a,b=0,0,1 whilen<max: yieldb a,b=b,a+b n=n+1

这就是定义generator的另一种方法               。如果一个函数定义中包含yield关键字               ,那么这个函数就不再是一个普通函数                   ,而是一个generator:

>>>fib(6) <generatorobjectfibat0x104feaaa0>

这里    ,最难理解的就是generator和函数的执行流程不一样                   。函数是顺序执行            ,遇到return语句或者最后一行函数语句就返回    。而变成generator的函数                  ,在每次调用next()的时候执行       ,遇到yield语句返回         ,再次执行时从上次返回的yield语句处继续执行            。

举个简单的例子                  ,定义一个generator          ,依次返回数字1      ,3                  ,5:

>>>defodd(): ...printstep1 ...yield1 ...printstep2 ...yield3 ...printstep3 ...yield5 ... >>>o=odd() >>>o.next() step1 1 >>>o.next() step2 3 >>>o.next() step3 5 >>>o.next() Traceback(mostrecentcalllast): File"<stdin>",line1,in<module> StopIteration

可以看到             ,odd不是普通函数   ,而是generator                  ,在执行过程中                ,遇到yield就中断,下次又继续执行                  。执行3次yield后               ,已经没有yield可以执行了                   ,所以    ,第4次调用next()就报错       。

回到fib的例子            ,我们在循环过程中不断调用yield                  ,就会不断中断         。当然要给循环设置一个条件来退出循环       ,不然就会产生一个数列出来                  。

同样的         ,把函数改成generator后                  ,我们基本上从来不会用next()来调用它          ,而是直接使用for循环来迭代:

>>>forninfib(6): ...printn ... 1 1 2 3 5 8

小结

generator是非常强大的工具      ,在Python中                  ,可以简单地把列表生成式改成generator             ,也可以通过函数实现复杂逻辑的generator          。

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
es6对象的方法名不可以是表达式(ES6–》对象扩展方法) 如何优化核心,提升突出优化表现?(掌握这些技巧,让你的更具优势!)