python高階(11)生成器

2022-05-09 07:18:07 字數 3558 閱讀 1992

利用迭代器,我們可以在每次迭代獲取資料(通過next()方法)時按照特定的規律進行生成。但是我們在實現乙個迭代器時,關於當前迭代到的狀態需要我們自己記錄,進而才能根據當前狀態生成下乙個資料。

為了達到記錄當前狀態,並配合next()函式進行迭代使用,我們可以採用更簡便的語法,即生成器(generator)。生成器是一類特殊的迭代器。

要建立乙個生成器,有很多種方法。第一種方法很簡單,只要把乙個列表生成式的 [ ] 改成 ( )

>>> l = [x**2 for x in range(5)]

>>> l

[0, 1, 4, 9, 16]

>>> g = (x**2 for x in range(5))

>>> g

at 0x7fb63d218750>

建立 l 和 g 的區別僅在於最外層的 [ ] 和 ( ) , l 是乙個列表,而 g 是乙個生成器。我們可以直接列印出列表l的每乙個元素,而對於生成器g,我們可以按照迭代器的使用方法來使用,即可以通過next()函式、for迴圈、list()等方法使用。

>>> next(g)

0>>> next(g)

1>>> next(g)

4>>> next(g)

9>>> next(g)

16>>> next(g)

traceback (most recent call last):

file "", line 1, in next(g)

stopiteration

>>> g = ( x**2 for x in range(5))

>>> for x in g:

print(x)

generator非常強大。如果推算的演算法比較複雜,用類似列表生成式的 for 迴圈無法實現的時候,還可以用函式來實現。

就像之前提到的斐波那切數列

注意,在用迭代器實現的方式中,我們要借助幾個變數(n、current、num1、num2)來儲存迭代的狀態。現在我們用生成器來實現一下。

>>> def fib(n):

current = 0

num1, num2 = 0, 1

while current < n:

num = num1

num1, num2 = num2, num1 + num2

current += 1

yield num

return '完成'

>>> f = fib(5)

>>> next(f)

0>>> next(f)

1>>> next(f)

1>>> next(f)

2>>> next(f)

3>>> next(f)

traceback (most recent call last):

file "", line 1, in next(f)

stopiteration: 完成

在使用生成器實現的方式中,我們將原本在迭代器__next__方法中實現的基本邏輯放到乙個函式中來實現,但是將每次迭代返回數值的return換成了yield,此時新定義的函式便不再是函式,而是乙個生成器了。

簡單來說:只要在def中有yield關鍵字的 就稱為 生成器

此時按照呼叫函式的方式( 案例中為f = fib(5) )使用生成器就不再是執行函式體了,而是會返回乙個生成器物件( 案例中為f ),然後就可以按照使用迭代器的方式來使用生成器了。

>>> for n in fib(5):

print(n)01

123>>>

但是用for迴圈呼叫generator時,發現拿不到generator的return語句的返回值。如果想要拿到返回值,必須捕獲stopiteration錯誤,返回值包含在stopiteration的value中:

>>> g = fib(5)

>>> while true:

try:

x = next(g)

print(f"value:")

except stopiteration as e:

print(f"生成器返回值:")

break

value:0

value:1

value:1

value:2

value:3

生成器返回值:完成

# 列表的記憶體開銷和執行時間

start_time = time.perf_counter()

list1 = [i for i in range(2, 10001, 2)]

cost_time = time.perf_counter()-start_time

print(f"記憶體開銷為位元組")

# 生成器的記憶體開銷和執行時間

start_time1 = time.perf_counter()

g = (i for i in range(2, 10001, 2))

cost_time1 = time.perf_counter()-start_time1

print(f"記憶體開銷為位元組")

結果

記憶體開銷為43048位元組

記憶體開銷為128位元組

通過結果,我們可以明顯的看出,生成器的記憶體開銷和執行速度要明顯比列表的要更節省記憶體,執行速度更快

如果有乙個包含100w個元素的列表,但是我們僅僅只想訪問前3個,那麼後面的列表元素占用的記憶體空間都是浪費的,這個時候我們沒必要建立完成的list,可以使用生成器,從而可以節省大量記憶體空間

可以使用next()函式讓生成器從斷點處繼續執行,即喚醒生成器(函式)

python3中的生成器可以使用return返回最終執行的返回值,而python2中的生成器不允許使用return返回乙個返回值(即可以使用return從生成器中退出,但return後不能有任何表示式)。

我們除了可以使用next()函式來喚醒生成器繼續執行外,還可以使用send()函式來喚醒執行。使用send()函式的乙個好處是可以在喚醒的同時向斷點處傳入乙個附加資料。

例子:執行到yield時,gen函式作用暫時儲存,返回i的值; temp接收下次c.send("python"),send傳送過來的值,c.next()等價c.send(none)

>>> def gen():

i = 0

while i < 5:

temp = yield i

print(temp)

i += 1

>>> f = gen()

>>> next(f)

0>>> f.send('haha')

haha

1>>> next(f)

none

2>>> f.send('haha')

haha

3>>>

python3生成器 Python3 生成器

python3 生成器 閱讀 125 發布於 2020 05 19 14 29 25 在python中,一邊迴圈一邊計算出元素的機制,稱為生成器 generator。生成器的優點 一次返回乙個結果,延遲計算。這對於大資料量處理,是個非常有用的優勢。占用記憶體量是工程師必須考慮的乙個問題。提高 可讀性...

《Python高階程式設計》(三)生成器

生成器是乙個函式,它並不執行並返回乙個單一值,而是按照順序返回乙個或多個值 生成器函式的特徵就是在函式內部有乙個或多個yield語句。python 2中,yield和return不能共存 python 3中可同時存在。yield語句 命令函式返回乙個值給呼叫者,但不會終止函式的執行。執行會暫時停頓直...

Python(九)生成器

該系列文章用來記錄一下自己在b站學習python時,進行上機練習用的 使用 pycharm 2020.3.3 慕課 python語言基礎與應用 北京大學 陳斌 字幕校對 編寫程式,輸入兩個數,輸出它們的商,採用例外處理來處理兩種錯誤,給出使用者友好的提示資訊 1 除數為0 2 輸入了非數值 try ...