生成器
生成器就是一個帶yield的函數(只要函數包含yield,函數調用就會返回一個生成器對象),普通的函數只能返回一次,但一個生成器能夠暫停執行並返回一個中間的結果,當生成器的next()方法被調用的時候,會從離開的地方繼續執行,並且能夠上次調用的所有局部變量保持不變。說得直白點,生成器就是一個特殊的函數,它能產生一列的結果而不只是產生單一結果。
生成器也是一個迭代器,擁有next方法並且行為與迭代器完全相同,可用於for循環中(for循環每次自動調用next方法直到拋出StopIteration異常
),並且定義一個生成器比定義一個迭代器簡單很多。
生成器的優點
- 可以保留函數的參數
- 每次調用next方法時,所使用的參數都是上一次調用所保留下來的,而不是新創建的,並且可以多次調用
- 生成器的定義比迭代器的定義簡單
- 占用空間小,每次調用才產生值,而不是產生完全后返回
簡單的生成器
生成器可以看作是一個迭代器,擁有next()方法,當一個真正的返回(調用return)或者函數結束沒有更多的值返回時(調用next()),會拋出StopIteration異常
用生成器實現斐波那契系數
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的返回值。
>>> f.next()
2
4.當調用next方法時生成器結束(遇到空的return語句或到達函數末尾),此次next將會拋出StopIteration異常
5.生成器函數中不允許有參數的return語句,如果出現,將會拋出SyntaxError: 'return' with argument inside generator
錯誤
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():要求生成器退出
1.send(value)
send是除了next方法以外另一個恢復生成器的方法;此時,yield必須是一個表達式,yield表達式返回的值就是調用send方法的參數,生成器從yield開始運行,直到再次遇到yield,並將yield的參數作為send方法的返回值
- 調用send傳入非None,生成器必須處於掛起狀態,否則將拋出異常。不過,未啟動的生成器仍可以使用None作為參數調用send
- 如果使用next恢復生成器,yield表達式的值將是None
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
2.close()
這個方法用於關閉生成器。對關閉的生成器后再次調用next或send將拋出StopIteration異常。
3.throw(type, value=None, traceback=None):
這個方法用於在生成器內部(生成器的當前掛起處,或未啟動時在定義處)拋出一個異常。
利用yield模擬線程並發
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)