1. 程式人生 > 實用技巧 >學點簡單的Python之Python生成器

學點簡單的Python之Python生成器

此文轉載自:https://blog.csdn.net/qq_43422111/article/details/112368651

學點簡單的Python之Python生成器

  大家好,我叫亓官劼(qí guān jié ),在CSDN中記錄學習的點滴歷程,時光荏苒,未來可期,加油~博主目前僅在CSDN中寫部落格,唯一部落格更新的地址為:亓官劼的部落格 ,同時正在嘗試在B站中做一些內容分享,B站主頁為: 亓官劼的B站主頁

本文原創為亓官劼,請大家支援原創,部分平臺一直在惡意盜取博主的文章!!!
若需聯絡博主,可以聯絡本人微信:qiguanjie2015


什麼是生成器?生成器能夠做什麼

在Python中,使用了yield的函式被稱為生成器,生成器返回的是一個迭代器的函式,只能用於迭代操作,在呼叫生成器執行的過程中,每次遇到 yield 時函式會暫停並儲存當前所有的執行資訊,返回 yield 的值, 並在下一次執行 next() 方法時從當前位置繼續執行。

生成器常用場景:例如我們需要生成一個有規律向前推進的列表,或者一個1-1億的列表等等,當我們列表中元素數量十分大時,記憶體會爆棧。但是如何我們元素間是有規律的,則我們可以利用生成器來解決這個問題。

例如一個簡單是生成器應用例項,利用生成器輸出1-1億的數。

list = (i for i in range(1,100000000))
for item in list:
    print(item)

注意這裡使用的是()而不是列表的[]。如果使用列表,記憶體將會爆棧,程式直接卡死,各位小夥伴有興趣的話可以自己嘗試一下哦!

如何建立一個生成器?如何使用生成器?

那生成器只能生成這樣連續的簡單數列嗎?當然不是!我們可以編寫自己的生成器函式,例如我們編寫一個斐波那契數列的生成器。

# 生成器函式 - 斐波那契數列
def fibonacci(n):
    # a為第一個數,b為第二個數,counter為當前是第幾個,迭代向前推進
    a, b, counter = 0, 1, 0
    while True:
        if counter > n:
            return
        yield a
        a, b = b, a + b
        counter += 1


# fib 是一個迭代器,由生成器返回生成
fib = fibonacci(10)

for item in fib:
    print(item)

輸出為:

0
1
1
2
3
5
8
13
21
34
55

這裡我們每次返回一個fibonacci數列的值,每次返回的值即通過yield返回的值,返回之後生成器中的狀態保持不變,等待下一次呼叫,當下一次呼叫來時,繼續執行直到通過yield返回下一個值,以此迴圈。生成器不是將所有數儲存在數列中,而是一個迭代器,每次返回時向前迭代。

next()和send()函式

我們可以利用next( )函式來獲取迭代器的下一個值,例如下面這個例子:

def gen():
    yield 1
    yield 2
    yield 3
    yield 4

# a是由生成器gen生成的一個迭代器
a = gen()
print(next(a))# 輸出a中下一個值
print(next(a))# 輸出a中下一個值
print(next(a))# 輸出a中下一個值
print(next(a))# 輸出a中下一個值

輸出結果為:

1
2
3
4

生成器即是迭代器也是可迭代物件,即我們可以通過next來依次獲取迭代器中的值,同時也可以通過之前例子中的迭代器直接獲取。

當前例子中我們迭代器中只有四個值,那麼當我們獲取四個值之後再次呼叫next(a)時,便會丟擲StopIteration異常,即當前迭代器沒法繼續向前迭代。

同時,我們也可以使用send()函式來獲取下一個值,但是與next()函式不同的是,send()函式需要一個引數,將這個引數傳送到yield表示式的值。例如下面這個例子:

def gen():
    temp = yield 1
    print(temp)
    temp = yield 2
    print(temp)
    temp = yield 3
    print(temp)
    temp = yield 4
    print(temp)

# a是由生成器gen生成的一個迭代器
a = gen()
print(next(a))# 輸出a中下一個值
print(next(a))# 輸出a中下一個值
print(next(a))# 輸出a中下一個值
print(next(a))# 輸出a中下一個值

這時我們的輸出為:

1
None
2
None
3
None
4

這裡與我們上面例子不同的是,我們每次yield返回後,將這個yield 1的值作為表示式賦值給temp,當我們直接使用next()獲取時,這個表示式的值為None,同時我們發現只輸出了三個None,這也驗證了我們之前說的,每次呼叫下一個值後,我們會停留在yield的位置,儲存所有狀態,直到下一次呼叫才會繼續向下走。

我們通過send()函式來獲取下一個值時,我們在send()函式中傳的引數將會作為yield 1表示式的值賦值給temp,例如下面的例子。

def gen():
    temp = yield 1
    print(temp)
    temp = yield 2
    print(temp)
    temp = yield 3
    print(temp)
    temp = yield 4
    print(temp)

# a是由生成器gen生成的一個迭代器
a = gen()
print(a.send(None))# 輸出a中下一個值,第一次執行生成器程式碼的時候,send函式必須要傳遞None進去,否則會報錯
print(a.send('qiguanjie1'))# 輸出a中下一個值,並傳入引數qiguanjie1給yield表示式
print(a.send('qiguanjie2'))# 輸出a中下一個值,並傳入引數qiguanjie2給yield表示式
print(a.send('qiguanjie3'))# 輸出a中下一個值,並傳入引數qiguanjie3給yield表示式

輸出為:

1
qiguanjie1
2
qiguanjie2
3
qiguanjie3
4

如果我們要使用send()來呼叫下一個值但我們不需要傳送訊息時,我們可以傳遞一個None進去,即a.send(None)

好了,今天的學點簡單的Python之Python生成器篇就到這裡了,我們下次再見!如果這篇文章對您有幫助的話,可以點贊關注博主一下,給博主一些鼓勵,哈哈~