python -- 生成器
2017-09-11 08:59 abce 阅读(344) 评论(0) 编辑 收藏 举报在for循环中,每次yield值后,控制权就返回给for循环
生成器类似于返回一个数组的函数。生成器有参数、可以被调用,并生成值的序列。和函数一次返回整个数组不同,生成器每次只是生成一个值,这样会占用很少的内存,并且调用者可以立即处理生成的值。概括来说,生成器看起来像个函数,但是使用起来像个迭代器。
Python提供的,在需要时才生成结果的工具:
-生成器函数:
使用def定义,但是每次使用yield生成返回值值、挂起、在继续运行。
-生成器表达式:
类似于列表推导,但不是创建一个结果列表,而是每次根据需要生成对象。
因为无论是生成器函数、还是生成器表达式都不是一次生成一个结果列表,这样可以节省内存空间,并将计算时间以迭代协议的方式切分开。
生成器函数:yield和return
生成器函数和常规函数有点类似,都是使用def定义。当创建后,自动实现迭代协议。
常规函数会返回值并退出。而迭代器函数返回一个值后会自动挂起、然后再次执行。
生成器函数和常规函数之间的主要区别是前者yield一个值,后者返回一个值。yield会挂起函数,返回一个值给调用者。
生成器是和迭代协议绑在一起的。可迭代的对象定义一个方法:__next__(),该方法要么返回迭代器的下一个值,要么抛出一个异常。
定义生成器的时候需要使用关键字:yield。
让我们来看个示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | >>> def counter(n): print ( "counter()" ) while True : yield n print ( "increment n" ) n + = 1 >>> c = counter( 2 ) >>> c <generator object counter at 0x000000000246D480 > >>> next (c) counter() 2 >>> next (c) increment n 3 >>> next (c) increment n 4 >>> c. next () increment n 5 >>> c. next () increment n 6 >>> |
1.关键字yield表明该函数不是一个常规函数,而是一个迭代器函数。
2.生成一个迭代器的实例,和调用常规函数类似。但是调用的时候并不真正执行函数代码。
3.counter()返回一个迭代器对象
比如,下面的迭代器生成数字的立方值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | >>> def cubic_generator(n): for i in range (n): yield i * * 3 >>> cg = cubic_generator( 3 ) >>> cg <generator object cubic_generator at 0x0000000002A72CF0 > >>> cg. next () 0 >>> cg. next () 1 >>> cg. next () 8 >>> cg. next () Traceback (most recent call last): File "<pyshell#32>" , line 1 , in <module> cg. next () StopIteration >>> |
在for循环中,每次yield值后,控制权就返回给for循环:
1 2 3 4 5 6 7 8 9 10 | >>> for i in cubic_generator( 5 ): print (i) 0 1 8 27 64 >>> |
如果用return代替yield:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | >>> def cubic_generator(n): for i in range (n): return i * * 3 >>> for i in cubic_generator( 5 ): print (i) Traceback (most recent call last): File "<pyshell#54>" , line 1 , in <module> for i in cubic_generator( 5 ): TypeError: 'int' object is not iterable >>> cubic_generator( 5 ) 0 >>> |
使用生成器的示例1:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | >>> def fib(): limit = 10 count = 0 a,b = 0 , 1 while True : yield a a,b = b,a + b if (count = = limit): break count + = 1 >>> for i in fib(): print (i) 0 1 1 2 3 5 8 13 21 34 55 >>> |
使用生成器实现斐波纳契数列:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | >>> def fib( max ): a,b = 0 , 1 while a < max : yield a a,b = b,a + b >>> for i in fib( 500 ): print (i) 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 >>> list (fib( 500 )) [ 0 , 1 , 1 , 2 , 3 , 5 , 8 , 13 , 21 , 34 , 55 , 89 , 144 , 233 , 377 ] >>> |
生成器表达式: 可推导的迭代器
迭代器和列表推导相结合,形成了一个新特性:生成器表达式。
生成器表达式和列表表达式类似,但是前者被小括号包含着,后者是用方括号包含的。
1 2 3 4 5 6 7 8 9 10 11 | >>> #列表推导 >>> [x * * 3 for x in range ( 5 )] [ 0 , 1 , 8 , 27 , 64 ] >>> >>> #生成器表达式 >>> (x * * 3 for x in range ( 5 )) <generator object <genexpr> at 0x0000000002BE0798 > >>> >>> list (x * * 3 for x in range ( 5 )) [ 0 , 1 , 8 , 27 , 64 ] >>> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | >>> gen = (x * * 3 for x in range ( 5 )) >>> gen. next () 0 >>> gen. next () 1 >>> gen. next () 8 >>> gen. next () 27 >>> gen. next () 64 >>> gen. next () Traceback (most recent call last): File "<pyshell#17>" , line 1 , in <module> gen. next () StopIteration >>> |
生成器:函数 vs 表达式
相同的迭代可以用生成器函数或生成器表达式实现。二者都可以自动迭代或手动迭代。
1 2 3 4 5 6 7 8 9 10 11 12 13 | >>> gen = (c * 5 for c in 'pyhton' ) >>> list (gen) [ 'ppppp' , 'yyyyy' , 'hhhhh' , 'ttttt' , 'ooooo' , 'nnnnn' ] >>> >>> def gen(x): for c in x: yield c * 5 >>> g = gen( 'python' ) >>> list (g) [ 'ppppp' , 'yyyyy' , 'ttttt' , 'hhhhh' , 'ooooo' , 'nnnnn' ] >>> |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)