python yield
一。深入研究
>>> def get_0_1_2(): ... yield 0 ... yield 1 ... yield 2 ... >>> get_0_1_2 <function get_0_1_2 at 0x00B2CB70> #函数类型 >>> generator = get_0_1_2() >>> generator <generator object get_0_1_2 at 0x00B1C7D8> #生成器 >>> generator.next() #第一次调用生成器的next方法时,生成器才开始执行生成器函数(而不是构建生成器时),直到遇到yield时暂停执行 0 >>> generator.next() #之后每次调用生成器的next方法,生成器将从上次暂停执行的位置恢复执行生成器函数,直到再次遇到yield时暂停 1 >>> generator.next() 2>>> generator.
next
() #当调用next方法时生成器函数结束(遇到空的return语句或是到达函数体末尾),则这次next方法的调用将抛出StopIteration异常
Traceback (most recent call last):
File
"<stdin>"
, line
1
,
in
<module>
StopIteration
因为直接调用next()到最后会抛出异常,所以一般使用for循环输出结果
>>> def test_return(): ... yield 4 ... return 0 ... File "<stdin>", line 3 SyntaxError: 'return' with argument inside generator
作为生成器,因为每次迭代就会返回一个值,所以不能显示的在生成器函数中return 某个值,包括None值也不行,否则会抛出“SyntaxError”的异常,
但是在函数中可以出现单独的return,表示结束该语句。
二。控制生成器
1.变量控制
class Bank(): # 创建银行,构建ATM机,只要没有危机,就可以不断地每次从中取100 crisis = False def create_atm(self): while not self.crisis: yield "$100"
2. send: Resumes the generator and "sends" a value that becomes the result of the current yield-expression
def consumer(): print "consumer start..." result = None while True: s = yield result result = s.split(",") c = consumer() #不调用则出错:TypeError: can't send non-None value to a just-started generator print c.send(None) # send(None) 或 next()启动协程 print c.send("a,b") # 向协程发送消息 print c.send("c,d") c.close() # 关协程 # print c.send("e,f") # 无法向已关闭的协程发送消息。
3.
def consumer(): while True: d = yield if not d :break print "consumer: ", d c = consumer() #创建消费者 c.send(None) #启动消费者 c.send(1) #生产数据,并提供给消费者 c.send(2) c.send(3) c.close()
三。示例
1.斐波那契数列
>>> def fibonacci(): ... a = b = 1 ... yield a ... yield b ... while True: ... a, b = b, a+b ... yield b ... >>> for num in fibonacci(): ... if num > 100: break ... print num, ... 1 1 2 3 5 8 13 21 34 55 89
看到while True可别太吃惊,因为生成器可以挂起,所以是延迟计算的,无限循环并没有关系。
2.读大文件
如果直接对文件对象调用 read() 方法,会导致不可预测的内存占用。好的方法是利用固定长度的缓冲区来不断读取文件内容。
def read_file(path): size = 1024 with open(path,'r') as f: while True: block = f.read(SIZE) if block: yield block else: return