1. 程式人生 > >【Python學習之十】yield之send方法

【Python學習之十】yield之send方法

下一條 lis 區別 但是 查找 接受 python 方法 完全

yield作用

  簡單地講,yield 的作用就是把一個函數變成一個 generator,帶有 yield 的函數不再是一個普通函數,Python 解釋器會將其視為一個 generator。下面以斐波拉契數列來做個說明:

# 普通的函數實現
def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        print(b)
        a, b = b, a + b
        n = n + 1
    return done
"""不足:
在 fab 函數中用 print 打印數字會導致該函數可復用性較差
因為其他函數無法獲得該函數生成的數列。
""" # 返回一個 List def fib(max): n, a, b = 0, 0, 1 L = [] while n < max: L.append(b) a, b = b, a + b n = n + 1 return L """不足 該函數在運行中占用的內存會隨著參數 max 的增大而增大,如果要控制內存占用,最好不要用 List 來保存中間結果,而是通過iterable對象來叠代。 """ # 使用yield def fab(max): n, a, b = 0, 0, 1 while
n < max: yield b # print b a, b = b, a + b n = n + 1 """ 帶有 yield 的函數不再是一個普通函數,Python 解釋器會將其視為一個 generator,
調用 fab(5) 不會執行fab函數,而是返回一個 iterable對象
"""

下面執行yield版的fab函數:

# 運行
for n in fab(5):
    print(n)

# 結果
1
1
2
3
5

  在 for 循環執行時,每次循環都會執行 fab 函數內部的代碼,執行到 yield b 時,fab 函數就返回一個叠代值,下次叠代時,代碼從 yield b 的下一條語句繼續執行,而函數的本地變量看起來和上次中斷執行前是完全一樣的,於是函數繼續執行,直到再次遇到 yield。

yield send方法

  關於生成器中的send方法,之前沒理解,只知道有一個next方法。通過下面代碼實例,記錄一下自己的理解:

def func1():  # 生成器函數
    x = yield 1
    print(This is x in func1: , x)
    x = yield x
    # print(‘This is x:‘, x)


f1 = func1()
print(This is next(f1): , next(f1))
# 當調用next(f1)方法時,python首先會執行func1方法的yield 1語句
# next方法返回值為yield關鍵字後面表達式的值,即為1
# 此時方法func1中斷執行,x的賦值以及之後的語句,不再執行

# 執行send方法或next方法:
print("This is f1.send(‘e‘):", f1.send(e))
# print("Second next:", next(f1))

# 當調用f1.send(‘e‘)方法時,恢復之前yield引起的中斷
# 繼續執行 x = yield 1,對x賦值
# 此時(yield 1)的返回值是send方法的參數值‘e‘,並將其賦值給x
# 然後繼續執行 print(‘This is x in func1: ‘, x)
# 執行結果是This is x in func1: e

# 當調用next方法—>print("Second next:", next(f1))
# func1會從之前的中斷—>yield 1語句,繼續運行
# 語句 print(‘This is x in func1: ‘, x) 將被執行。
# 但是,此時yield 1的返回值是None,並將其賦值給x
# 因此,執行結果是:This is x in func1: None

# 如果調用f1.send(‘e‘)方法,則接下來繼續執行,會遇到yield x語句
# func1再次被掛起。
# 此時,send方法的返回值為yield關鍵字後面表達式的值,即是x的值‘e‘
# 執行結果是:This is f1.send(‘e‘): e
# 如果func1方法內無 yield x 語句,將會報錯:StopIteration

# 如果此時再次調用send方法
# print("This is f1.send(‘f‘):", f1.send(‘f‘))

# 此時表達式(yield x)的返回值定義為send方法參數的值,即為‘f‘
# 接下來x = yield x 這一賦值語句會將x的值置為‘f‘
# 繼續運行,func1方法執行完畢,拋出StopIteration異常
# f1.send(‘f‘)也就沒有返回值了。
# 但是,我們可以在func1方法,x = yield x語句後,中加入一條語句
# print(‘This is last x: ‘, x),用來測試x的值‘f’

總之,send方法和next方法的區別在於,執行send方法時,會首先把send方法內的參數賦值給上一次掛起的yield語句的返回值。但是需要註意,在一個生成器對象沒有執行next方法之前,由於沒有yield語句被掛起,所以執行send方法會報錯:

TypeError: cant send non-None value to a just-started generator

但是,下面的語句是可行的:

f2 = func1()
print("Send None value: ", f3.send(None))
# 運行結果
# Send None value:
1

當send方法的參數為None時,它與next方法完全等價。但是註意,雖然上面的代碼可以接受,但是不規範。所以,在調用send方法之前,還是先調用一次next方法為好。

  以上,就是我通過查找資料,搞清楚yield 中send方法的過程與心得。感謝:https://blog.csdn.net/hedan2013/article/details/56293173 提供的參考。

【Python學習之十】yield之send方法