生成器表达式和列表解析:
(x+1 for x in [1,2,3,4,5]) #生成器表达式 [x+1 for x in [1,2,3,4,5]] #列表解析 (x+1 for x in [1,2,3,4,5,6] if x>0) ((x,y) for x in range(3) for y in range(x)) (x for x in (y.dosomething() for y in [1,2,3,4,5]) if x>0)
一个带有yield的函数就是一个generator,它和普通函数不同,生成一个generator看起来像函数调用。但不会执行任何函数代码,直到对其调用next()(在for循环中会自动调用next())才会开始执行。虽然执行流程仍然按函数的流程执行,但每执行到一个yield语句就会中断,并返回一个迭代至,下次执行时从yield的下一个语句继续执行。看起来就好像一个函数在正常执行的过程中被yield中断了数次。每次中断都会通过yield返回当前的迭代值。
如,输出斐波那契数列:
def fab(max): a=0 b=1 i=0 while(i<max): yield b a,b=b,a+b i=i+1 for i in fab(5): print i
判断一个函数是否是一个特殊的generator函数:
>>>from inspect import isgeneratorfunction >>>isgeneratorfunction(fab)
fab是一个generator function,而fab(5)是调用fab返回的一个generator ,好比是类和类的实例的区别。
>>>import types >>>isinstance(fab,types.GeneratorType) False >>>isinstance(fab(1),types.GeneratorType) True
return的作用:
作为生成器,因为每次迭代就会返回一个值,所以不能显示的在生成器函数中return某个值,包括None的值也不行,但在函数中可以出现单独的return,表示结束该语句。
send()和next()函数:
其实,next()和send()在一定意义上作用是相似的,区别是send()可以给yield表达式传递值,而next()不可以,只能传递None进行。因此,我们可以看作c.next()和c.send(None)是一样的。
def a(n): while True: b=yield n print b >>>b=a(5) >>>b.next() 5 >>>b.next() None 5 >>>c=a(5) >>>c.next() 5 >>>c.send(3) 3 5
由此可见,yield表达式的值是由send函数传递的值决定的,而yield返回的值不受影响。
def a(n): i=0 while i<n: i=yield i i=i+1 >>>b=a(10) >>>a.next() 0 >>>a.next() 出现TypeError的错误 >>>c=a(5) >>>c.next() 0 >>>c.send(2) 3 #此时,传入2,则i=2,然后执行i=i+1,i变成了3,yield返回3 >>>c.send(9) 出现StopIteration的异常
采用yield读取文件:
如果直接读取文件,会导致不可预测的内存占用。好的方法就是利用固定长度的缓存来不断的读取文件的内容。通过yield,我们不再需要编写读文件的迭代类就可以轻松实现文件读取:
def read_file(fpath): block_size=1024 with open(fpath) as f: while True: block=f.read(block_size) if block: yield block else: return
原文:http://my.oschina.net/935572630/blog/391034