Python Generator
本文对《Python Cookbook》中对于生成器部分的讲解进行总结和分析:
对于生成器我们一般这样使用:
CODE 1:
lxw Python_Cookbook$ p Python 3.4.0 (default, Apr 11 2014, 13:05:18) [GCC 4.8.2] on linux Type "help", "copyright", "credits" or "license" for more information. >>> def countdown(n): ... print("Start to count from", n) ... while n > 0: ... yield n ... n -= 1 ... print("Done!") ... >>> c = countdown(3) >>> c <generator object countdown at 0xb7234c5c> >>> for item in c: ... print(item) ... Start to count from 3 3 2 1 Done!
让我们用下面的代码来理解生成器的底层工作机制(underlying mechanics):[接上面的代码]
CODE 2:
>>> d = countdown(3) #没有输出 "Start to count from 3" >>> d <generator object countdown at 0xb711a43c> >>> next(d) #输出 Start to count from 3 3 >>> next(d) 2 >>> next(d) 1 >>> next(d) #继续next出现异常 Done! Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration >>>
分析:
首先, 生成器和普通函数在形式上是一样的. 如果在普通的函数中出现了yield语句,那么这个函数就变成了生成器.
在CODE 2部分, 执行语句d = countdown(3)后, 并没有任何的输出显示. 在执行了next(d)语句之后才出现输出. 这说明:
生成器中的语句只有在next语句执行的时候才会被执行.(The key feature is that a generator function only runs in
response to “next” operations carried out in iteration.) . 当生成器中的元素全部取完后, 再执行next就会抛出异常.
在CODE 1部分, 执行语句c = countdown(3)后, 也没有任何的输出显示(这是合理的, 并且与前面的分析一致). 如果通过这
种方式使用生成器, 则在for循环中会自动获取生成器中的元素, 且不用考虑会因为next而抛出异常.(However, the for statement
that’s usually used to iterate takes care of these details, so you don’t normally need to worry about them.)
More:
@1: Use the built-in functions.
@2: Use join() instead of "+" to deal with strings.
@3: Use local variables instead of global variables, it's much faster.
@4: Use while 1 instead of while True.
@5:生成器可以帮你节省内存,提高性能。如果正在加载视频,那么可以不需要一下子全部加载完。
>>> chunk = ( 1000 * i for i in xrange(1000)) >>> chunk <generator object <genexpr> at 0x7f65d90dcaa0> >>> chunk.next() 0 >>> chunk.next() 1000 >>> chunk.next() 2000
chunk.next() Python 2 和 next(chunk) Python3 都可以
Reference:
Python 性能小贴士 (第1部分): https://pycoders-weekly-chinese.readthedocs.org/en/latest/issue1/python-performance-tips-part-1.html?highlight=php