什么是yield?
一句話理解:讓普通函數,變成一個生成器(generator)[一個特殊的函數],函數里碰到yield就返回一次值。
yield 關鍵字就可以理解成和return一樣功能,返回一個值。
生成器,生成器,就是使用了next才會生成一段yield的值。就是next指揮它跑一段,碰到yield就停下來,下次再從上次停的地方開始跑。
一個例子:
def foo():
print("starting...")
while True:
res = yield 4
print("res:",res)
g = foo()
print(next(g))
print("*"*20)
print(next(g))
代碼輸出:
starting... 4 ******************** res: None 4
我直接解釋代碼運行順序,相當于代碼單步調試:
1.程序開始執行以后,因為foo函數中有yield關鍵字,所以foo函數并不會真的執行,而是先得到一個生成器g(相當于一個對象)
2.直到調用next方法,foo函數正式開始執行,先執行foo函數中的print方法,然后進入while循環
3.程序遇到yield關鍵字,然后把yield想想成return,return了一個4之后,程序停止,并沒有執行賦值給res操作,此時next(g)語句執行完成,所以輸出的前兩行(第一個是while上面的print的結果,第二個是return出的結果)是執行print(next(g))的結果,
4.程序執行print("*"*20),輸出20個*
5.又開始執行下面的print(next(g)),這個時候和上面那個差不多,不過不同的是,這個時候是從剛才那個next程序停止的地方開始執行的,也就是要執行res的賦值操作,這時候要注意,這個時候賦值操作的右邊是沒有值的(因為剛才那個是return出去了,并沒有給賦值操作的左邊傳參數),所以這個時候res賦值是None,所以接著下面的輸出就是res:None,
6.程序會繼續在while里執行,又一次碰到yield,這個時候同樣return 出4,然后程序停止,print函數輸出的4就是這次return出的4.
總結:也就是有yield的函數,是生成器,生成器在調用的時候并不會真正執行【g = foo() 這樣是不會真正執行】
只有調用了next(g),才會真正執行到碰到有yield的地方,然后就返回yield的值(比如yield 4)。
下一次再調用next(g)時,從剛剛yield返回的后面開始執行。直到下一次碰到next()
----------------------------------------------------
另一個例子:斐波那契(Fibonacci)數列是一個非常簡單的遞歸數列,除第一個和第二個數外,任意一個數都可由前兩個數相加得到。
計算斐波那契(Fibonacci)數列。
#!/usr/bin/python
# -*- coding: UTF-8 -*-
def fab(max):
n, a, b = 0, 0, 1
while n < max:
yield b # 使用 yield
# print b
a, b = b, a + b
n = n + 1
for n in fab(5):
print n
在 for 循環中會自動調用 next()。
當函數執行結束時,generator 自動拋出 StopIteration 異常,表示迭代完成。在 for 循環里,無需處理 StopIteration 異常,循環會正常結束。
也可以手動調用next()
>>>f = fab(5) >>> f.next() 1 >>> f.next() 1 >>> f.next() 2 >>> f.next() 3 >>> f.next() 5 >>> f.next() Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration
總結
- 上一篇: 【笔记】3D相机与测量原理
- 下一篇: 一个简单的Linux后门程序的实现