生成器就是一個帶yield的函數(只要函數包含yield,函數調用就會返回一個生成器對象),普通的函數只能返回一次,但一個生成器可以暫停執行並返回一箇中間的結果,當生成器的next()方法被調用的時候,會從離開的地方繼續執行,而且可以上次調用的全部局部變量保持不變。說得直白點,生成器就是一個特殊的函數,它能產生一列的結果而不僅是產生單一結果。
生成器也是一個迭代器,擁有next方法而且行爲與迭代器徹底相同,可用於for循環中(for循環每次自動調用next方法直到拋出StopIteration異常
),而且定義一個生成器比定義一個迭代器簡單不少。html
生成器能夠看做是一個迭代器,擁有next()方法,當一個真正的返回(調用return)或者函數結束沒有更多的值返回時(調用next()),會拋出StopIteration異常
python
用生成器實現斐波那契係數編程
def fab(max): a = 1 b = 1 i = 0 while i<max: yield b a,b = b,a+b i += 1 it = fab(5) for i in range(7): print it.next() # 1 # 2 # 3 # 5 # 8 # Traceback (most recent call last): # File "test.py", line 13, in <module> # print it.next() # StopIteration
1.當第1次調用生成器函數的時候,並不運行函數(如函數中有print語句,並不執行),**只是構建生成器對象*,並將生成器返回**,生成器函數可帶參數也可不帶參數閉包
>>> def fab(max): ... a,b,i = 1,1,0 ... while i<max: ... yield b ... a,b = b,a+b ... i +=1 ... >>> f = fab(10) >>> type(f) <type 'generator'>
2.當第1次調用生成器的next方法時,生成器纔開始執行生成器函數(並非構建,此時運行1中說的print語句),直到遇到yield暫停執行,並將yield的參數做爲這次next的返回值。併發
>>> f.next() 1
3.以後每次調用next方法,生成器將恢復環境並從上次運行的地方開始從新開始執行,直到再次遇到yield時暫停,而且將yield的參數做爲next的返回值。app
>>> f.next() 2
4.當調用next方法時生成器結束(遇到空的return語句或到達函數末尾),這次next將會拋出StopIteration異常
5.生成器函數中不容許有參數的return語句,若是出現,將會拋出SyntaxError: 'return' with argument inside generator
錯誤ide
def fab(max): a = 1 b = 1 while i<max: yield b a,b = b,a+b i += 1 return False it = fab(5) # File "test.py", line 8 # return False # SyntaxError: 'return' with argument inside generator
6.生成器函數在每次暫停執行時,函數體內的全部變量都將被封存(freeze)在生成器中,並將在恢復執行時還原,而且相似於閉包,即便是同一個生成器函數返回的生成器,封存的變量也是互相獨立的。函數式編程
send():將值返回給生成器
throw():在生成器中拋出異常
close():要求生成器退出函數
send是除了next方法之外另外一個恢復生成器的方法;此時,yield必須是一個表達式,yield表達式返回的值就是調用send方法的參數,生成器從yield開始運行,直到再次遇到yield,並將yield的參數做爲send方法的返回值.net
def gener(): name = 'not input' while True: name = yield name if name == None: name = "not input" else: name = "I'm " + name it = gener() print it.send(None) print it.send("zhainankl") print it.next() # not input # I'm zhainankl # not input
這個方法用於關閉生成器。對關閉的生成器後再次調用next或send將拋出StopIteration異常。
這個方法用於在生成器內部(生成器的當前掛起處,或未啓動時在定義處)拋出一個異常。
def thread1(): for x in range(4): yield x def thread2(): for x in range(4,8): yield x threads=[] threads.append(thread1()) threads.append(thread2()) def run(threads): #寫這個函數,模擬線程併發 pass run(threads)
def run(threads): for t in threads: try: print t.next() except StopIteration: pass else: threads.append(t)