網(wǎng)站建設(shè)中 html營銷課程
文章目錄
- 一、概述
- 二、生成器
- 1)生成器和迭代器的區(qū)別
- 2)生成器創(chuàng)建方式
- 1、通過生成器函數(shù)創(chuàng)建
- 2、通過生成器表達(dá)式創(chuàng)建
- 3)生成器表達(dá)式
- 4)yield關(guān)鍵字
- 5)生成器函數(shù)
- 6)return 和 yield 異同
- 7)yield的使用方法
- 8)for與next
- 9)send的使用
- 三、協(xié)程進(jìn)階
- 1)生成器與協(xié)程關(guān)系
- 2)協(xié)程實現(xiàn)原理
- 3)協(xié)程實現(xiàn)方式
一、概述
-
生成器是一種在 Python 中的迭代器生成器。生成器是一個函數(shù),它生成一個迭代器。當(dāng)生成器函數(shù)被調(diào)用時,它不會立即執(zhí)行,而是返回一個生成器對象,該對象可以被用于迭代。生成器可以利用 yield 語句在函數(shù)內(nèi)部生成值,并在函數(shù)調(diào)用者處接收這些值。
-
協(xié)程是一種高效的、內(nèi)存友好的、線程內(nèi)的并發(fā)技術(shù),它可以讓您在單個線程內(nèi)并發(fā)地執(zhí)行多個任務(wù)。協(xié)程是通過使用 async 關(guān)鍵字實現(xiàn)的,并可以在 Python 中的
asyncio
庫中使用。與線程不同,協(xié)程不需要額外的系統(tǒng)線程,因此它們比線程更高效、更靈活。
在簡單的說法,生成器用于生成一系列的值,而協(xié)程用于在單個線程中并發(fā)執(zhí)行多個任務(wù)。
二、生成器
生成器表達(dá)式本質(zhì)上就是一個迭代器,是定義迭代器的一種方式,是允許自定義邏輯的迭代器。生成器使用generator
表示。
-
生成器可以使用 for 循環(huán)或 next() 函數(shù)來遍歷。當(dāng)生成器對象被創(chuàng)建時,它會保存函數(shù)的當(dāng)前狀態(tài),并在每次調(diào)用 next() 或 for 循環(huán)時從當(dāng)前狀態(tài)開始執(zhí)行,直到遇到 yield 語句為止。
-
當(dāng)生成器遇到
yield
語句時,它會生成當(dāng)前的值,并保存函數(shù)的當(dāng)前狀態(tài),以便下次調(diào)用時可以從該狀態(tài)開始繼續(xù)執(zhí)行。當(dāng)生成器再次被調(diào)用時,它會繼續(xù)執(zhí)行從上次暫停的地方開始,直到遇到下一個yield
或者return
語句,或者函數(shù)結(jié)束為止。
下面是一個生成器函數(shù)的示例:
def my_generator():for i in range(3):yield igen = my_generator()
for i in gen:print(i)
輸出:
0
1
2
從上面的示例可以看出,生成器的工作原理是通過保存函數(shù)的當(dāng)前狀態(tài),以便每次調(diào)用時從當(dāng)前狀態(tài)開始繼續(xù)執(zhí)行,并使用 yield
語句生成值的。
1)生成器和迭代器的區(qū)別
生成器和迭代器是 Python 中的兩個相關(guān)的概念,但是有一些區(qū)別:
-
定義:生成器是一種特殊的迭代器,它可以生成一系列的值,而迭代器是一個對象,它實現(xiàn)了 iter 和 next 方法,可以返回一個值的序列。
-
創(chuàng)建:生成器可以通過定義生成器函數(shù),在函數(shù)內(nèi)部使用 yield 語句生成值;迭代器可以通過定義迭代器類,在類中實現(xiàn) iter 和 next 方法。
-
效率:生成器函數(shù)在生成值時只需要暫停函數(shù)的執(zhí)行,因此它具有更高的效率;迭代器類需要維護(hù)一個對象狀態(tài),因此效率較低。
-
用途:生成器適用于生成大量的數(shù)據(jù),因為它可以在生成數(shù)據(jù)時保存函數(shù)的狀態(tài),從而避免占用大量內(nèi)存;迭代器適用于處理少量數(shù)據(jù),因為它需要創(chuàng)建一個對象維護(hù)狀態(tài)。
因此,在實際開發(fā)中,我們可以根據(jù)數(shù)據(jù)量和處理效率的需求來選擇使用生成器或迭代器。
2)生成器創(chuàng)建方式
在 Python 中,可以通過以下兩種方式創(chuàng)建生成器:
1、通過生成器函數(shù)創(chuàng)建
通過在函數(shù)中使用 yield 語句,可以將函數(shù)變?yōu)樯善骱瘮?shù),每次調(diào)用生成器函數(shù)時,可以生成一個生成器。
例如:
def generator_example():yield 1yield 2yield 3gen = generator_example()
print(next(gen))
print(next(gen))
print(next(gen))
2、通過生成器表達(dá)式創(chuàng)建
生成器表達(dá)式是一種簡寫的生成器創(chuàng)建方式,它基于列表推導(dǎo)式的語法。
例如:
gen = (x for x in range(3))
print(next(gen))
print(next(gen))
print(next(gen))
以上是生成器的兩種創(chuàng)建方式,您可以根據(jù)實際需求選擇使用。
3)生成器表達(dá)式
生成器表達(dá)式是一種簡寫的生成器創(chuàng)建方式,它基于列表推導(dǎo)式的語法。
例如:
gen = (x for x in range(3))
print(next(gen))
print(next(gen))
print(next(gen))
在上面的例子中,我們使用生成器表達(dá)式創(chuàng)建了一個生成器,該生成器生成從 0 到 2 的整數(shù)。然后,我們使用 next()
函數(shù)逐個迭代生成器中的值。
4)yield關(guān)鍵字
yield
關(guān)鍵字是 Python 中的一個關(guān)鍵字,用于生成器函數(shù)中。它允許一個函數(shù)在生成值時暫停其執(zhí)行,以便在稍后恢復(fù)其執(zhí)行并生成下一個值。這使生成器函數(shù)成為一種特殊的函數(shù),可以按需生成一系列值。
5)生成器函數(shù)
生成器函數(shù)是 Python 中特殊的函數(shù),該函數(shù)可生成一個生成器。與普通函數(shù)不同,生成器函數(shù)可以在每次被調(diào)用時生成一個生成器,并在生成器中生成一系列值。
生成器函數(shù)通過使用 yield
語句創(chuàng)建生成器。每當(dāng)函數(shù)執(zhí)行到 yield
語句時,生成器函數(shù)的執(zhí)行就會暫停,并返回 yield 語句后面的值。當(dāng)再次調(diào)用生成器函數(shù)時,它將從上次暫停的位置繼續(xù)執(zhí)行,直到遇到下一個 yield
語句,或者函數(shù)返回。
例如:
def generator_example():yield 1yield 2yield 3gen = generator_example()
print(next(gen))
print(next(gen))
print(next(gen))
在上面的例子中,我們定義了一個生成器函數(shù) generator_example
,該函數(shù)通過使用 yield
語句生成了三個整數(shù):1、2 和 3。然后,我們通過調(diào)用該函數(shù)并將其結(jié)果分配給生成器 gen 來創(chuàng)建生成器,并使用 next()
函數(shù)逐個迭代生成器中的值。
6)return 和 yield 異同
return
和 yield
都是用于在函數(shù)中終止執(zhí)行的關(guān)鍵字,但是它們的作用是不同的。
-
return
:當(dāng)函數(shù)調(diào)用 return 時,函數(shù)立即終止執(zhí)行,并返回一個值(如果存在)給調(diào)用者。該值通常表示函數(shù)的最終結(jié)果。 -
yield
:當(dāng)生成器函數(shù)調(diào)用 yield 時,它僅暫停其執(zhí)行并生成一個值,但不終止函數(shù)。在下一次調(diào)用該生成器時,它將恢復(fù)其執(zhí)行,直到遇到下一個yield
或終止函數(shù)。
因此,yield
是生成器函數(shù)的一個關(guān)鍵字,可以使生成器生成一系列值,而 return
是一般函數(shù)的一個關(guān)鍵字,它返回一個值并終止函數(shù)。
7)yield的使用方法
yield
關(guān)鍵字用于生成器函數(shù)。在生成器函數(shù)中,我們可以使用 yield 關(guān)鍵字生成一系列值,而無需暫停整個函數(shù)。
例如,以下是使用 yield
關(guān)鍵字的簡單生成器函數(shù)的例子:
def simple_generator():yield 1yield 2yield 3yield 4yield 5gen = simple_generator()
print(next(gen)) # Output: 1
print(next(gen)) # Output: 2
print(next(gen)) # Output: 3
print(next(gen)) # Output: 4
print(next(gen)) # Output: 5
我們可以使用 for
循環(huán)或 next()
函數(shù)迭代生成器中的值,如下所示:
for value in simple_generator():print(value)# Output:
# 1
# 2
# 3
# 4
# 5
【注意】生成器函數(shù)只能迭代一次,所以請確保在使用生成器函數(shù)時存儲其返回值。
8)for與next
在使用生成器時,我們可以使用兩種不同的方法來迭代生成器中的值:for 循環(huán)
和 next()
函數(shù)。
- for 循環(huán):通過使用 for 循環(huán),我們可以在生成器中迭代所有值。例如:
def simple_generator():yield 1yield 2yield 3for value in simple_generator():print(value)# Output:
# 1
# 2
# 3
- next() 函數(shù):通過使用 next() 函數(shù),我們可以手動控制生成器的迭代。例如:
def simple_generator():yield 1yield 2yield 3gen = simple_generator()
print(next(gen)) # Output: 1
print(next(gen)) # Output: 2
print(next(gen)) # Output: 3
【注意】在生成器迭代完所有的值后,再使用
next()
函數(shù)將導(dǎo)致拋出 StopIteration 異常。因此,在使用 next() 函數(shù)時,請確保捕獲該異常。
9)send的使用
send()
方法是生成器的一種方法,它允許我們在生成器函數(shù)內(nèi)部向生成器發(fā)送數(shù)據(jù)。該方法允許生成器接收外部數(shù)據(jù),并使用這些數(shù)據(jù)生成結(jié)果。
在使用 send()
方法時,我們需要在生成器函數(shù)中使用 yield
表達(dá)式來接收數(shù)據(jù),如下所示:
def simple_generator():result = yieldprint("Received data:", result)gen = simple_generator()
next(gen)
gen.send("Hello, World!")
# Output: Received data: Hello, World!
【注意】第一次使用 send() 方法之前,我們需要調(diào)用 next() 函數(shù),以啟動生成器函數(shù)。此外,使用 send() 方法將導(dǎo)致拋出 StopIteration 異常,因此請確保在使用該方法時進(jìn)行異常處理。
三、協(xié)程進(jìn)階
協(xié)程(Coroutine)是一種編程技巧,用于在多任務(wù)環(huán)境中實現(xiàn)輕量級的任務(wù)切換。與線程不同,協(xié)程不需要創(chuàng)建新的系統(tǒng)級線程,并且消耗的資源也比線程更少。因此,協(xié)程可以比線程更高效地完成任務(wù)。在我上篇的文章已經(jīng)講解了:IO模型和協(xié)程介紹
1)生成器與協(xié)程關(guān)系
生成器和協(xié)程是相關(guān)但有所不同的概念。生成器是一種特殊的迭代器,可以生成一系列的值,每次迭代時只返回一個值。生成器可以使用 yield 關(guān)鍵字來暫停執(zhí)行,并在下一次調(diào)用時繼續(xù)執(zhí)行。
-
協(xié)程是一種并發(fā)編程技術(shù),可以在單一線程中實現(xiàn)多個任務(wù)的并行執(zhí)行。與線程不同,協(xié)程不需要創(chuàng)建新的系統(tǒng)級線程,并且消耗的資源也比線程更少。協(xié)程可以使用
yield
關(guān)鍵字來暫停執(zhí)行,并在下一次調(diào)用時繼續(xù)執(zhí)行。 -
因此,生成器可以用于實現(xiàn)協(xié)程,但它們不是協(xié)程的必需條件。在 Python 中,可以使用
asyncio
庫來實現(xiàn)協(xié)程,該庫不需要使用生成器。不過,在實現(xiàn)協(xié)程時,生成器確實可以作為一種有效的工具,幫助開發(fā)者實現(xiàn)協(xié)程的暫停和恢復(fù)。
2)協(xié)程實現(xiàn)原理
協(xié)程的實現(xiàn)主要是通過一種叫做 “協(xié)程調(diào)度器” 的技術(shù)實現(xiàn)的,這種技術(shù)能夠在不創(chuàng)建新的線程的情況下,在單一線程中按需切換協(xié)程的執(zhí)行。協(xié)程調(diào)度器會管理當(dāng)前正在運行的協(xié)程以及等待執(zhí)行的協(xié)程,并在每個協(xié)程執(zhí)行完后切換到下一個協(xié)程。
3)協(xié)程實現(xiàn)方式
在 Python 中,可以使用 asyncio
庫來實現(xiàn)協(xié)程。協(xié)程函數(shù)可以使用 async
關(guān)鍵字標(biāo)記,表示該函數(shù)是一個協(xié)程函數(shù)。在協(xié)程函數(shù)中,可以使用 await
關(guān)鍵字等待其他協(xié)程完成,從而實現(xiàn)協(xié)程的切換。
在 Python 中,可以使用 asyncio
庫來實現(xiàn)協(xié)程。下面是一個簡單的例子:
import asyncioasync def task1():print("Task 1 is running")await asyncio.sleep(1)print("Task 1 is complete")async def task2():print("Task 2 is running")await asyncio.sleep(1)print("Task 2 is complete")async def main():task1_coro = task1()task2_coro = task2()await asyncio.gather(task1_coro, task2_coro)if __name__ == "__main__":asyncio.run(main())
上面的代碼中,task1
和 task2
是兩個協(xié)程函數(shù),它們可以在單獨的任務(wù)中并行執(zhí)行。main
函數(shù)是協(xié)程的入口,在這個函數(shù)中,我們創(chuàng)建了兩個協(xié)程的對象 task1_coro
和 task2_coro
,并通過 asyncio.gather
函數(shù)將它們并行執(zhí)行。最后,我們通過 asyncio.run
函數(shù)啟動了整個協(xié)程。
運行上面的代碼,可以得到以下輸出:
Task 1 is running
Task 2 is running
Task 1 is complete
Task 2 is complete
可以看到,協(xié)程中的任務(wù)是并行執(zhí)行的,因此我們可以充分利用 CPU 的資源,提高程序的執(zhí)行效率。
Python 高級編程之生成器與協(xié)程進(jìn)階講解就先到這里了,有任何疑問歡迎給我留言,后續(xù)會持續(xù)更新相關(guān)技術(shù)文章,請小伙伴耐心等待,也可以關(guān)注我的公眾號【大數(shù)據(jù)與云原生技術(shù)分享】進(jìn)行深入技術(shù)交流~