溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

生成器Generator的原理及用法

發(fā)布時(shí)間:2021-07-06 09:46:59 來(lái)源:億速云 閱讀:310 作者:chen 欄目:web開(kāi)發(fā)

本篇內(nèi)容主要講解“生成器Generator的原理及用法”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“生成器Generator的原理及用法”吧!

基本用法

我們知道,函數(shù)體包含 yield 關(guān)鍵字的函數(shù)不是一個(gè)普通函數(shù)。這種函數(shù)叫做 生成器 ( generator  ),一般用于循環(huán)處理結(jié)構(gòu),應(yīng)用得當(dāng)可以極大優(yōu)化內(nèi)存使用效率。例如,設(shè)計(jì)一個(gè)函數(shù),打開(kāi)文件并將每一行轉(zhuǎn)成大寫(xiě)并返回:

def read_file_upper(path):     lines = []     with open(path) as f:         for line in f:             lines.append(line.upper())     return lines

這個(gè)版本的函數(shù),在內(nèi)部創(chuàng)建了一個(gè) list 對(duì)象,用于保存轉(zhuǎn)換結(jié)果。for  循環(huán)則遍歷文件每一行,將其轉(zhuǎn)成大寫(xiě)并追加到列表中。這樣一來(lái),文件中的每一行均需要保存在列表中,如果文件很大,內(nèi)存開(kāi)銷可想而知。

我們可以借助 yield 關(guān)鍵字,將 read_file_upper 函數(shù)改成生成器版本。函數(shù)主體邏輯沒(méi)有任何變化,只是將每行數(shù)據(jù)的處理結(jié)果通過(guò)  yield 逐個(gè)返回,而不是收集到 list 對(duì)象后再返還。

def iter_file_upper(path):     with open(path) as f:         for line in f:             yield line.upper()

如果現(xiàn)在有一個(gè)文本文件 data.txt ,里面包含以下內(nèi)容:

hello, world life is short, use python my wechat id is: coding-fan bye

用 iter_file_upper 生成器,我們可以這樣對(duì)它進(jìn)行處理:

>>> for line in iter_file_upper('text.txt'): ...     print(line.strip()) HELLO, WORLD LIFE IS SHORT, USE PYTHON MY WECHAT ID IS: CODING-FAN BYE

iter_file_upper 生成器用法與 read_file_upper  函數(shù)大致相同,但它不會(huì)一次性拿住文件所有數(shù)據(jù)行,而是逐行處理、逐個(gè)返回,這樣便將內(nèi)存使用量降到最低。

行為觀察

那么,生成器為什么會(huì)有這樣的奇效呢?我們接著觀察:

>>> g = iter_file_upper('text.txt') >>> g <generator object iter_file_upper at 0x103becd68>

我們調(diào)用 iter_file_upper 后,得到一個(gè)生成器對(duì)象,而不是文件處理結(jié)果,這時(shí) iter_file_upper 還未開(kāi)始執(zhí)行。

當(dāng)我們調(diào)用 next 函數(shù)從生成器接收下一個(gè)數(shù)據(jù)時(shí),iter_file_upper 開(kāi)始執(zhí)行并在 yield  處停下來(lái),并把第一行的處理結(jié)果返回給我們:

>>> next(g) 'HELLO, WORLD\n'

這時(shí),生成器處于暫停狀態(tài),沒(méi)有我們的指令,它不會(huì)接著處理第二行數(shù)據(jù)。

當(dāng)我們?cè)俅螆?zhí)行 next 函數(shù)時(shí),生成器再次恢復(fù)執(zhí)行,處理下一行數(shù)據(jù)并在 yield 處再次暫停:

>>> next(g) 'LIFE IS SHORT, USE PYTHON\n'

生成器記住了自己的執(zhí)行進(jìn)度,每次調(diào)用 next 函數(shù),它總是處理并生產(chǎn)下一個(gè)數(shù)據(jù),完全不用我們瞎操心:

>>> next(g) 'MY WECHAT ID IS: CODING-FAN\n' >>> next(g) 'BYE\n'

當(dāng) iter_file_upper 代碼邏輯執(zhí)行完畢,它將給 next 拋一個(gè)異常,以此通知調(diào)用者它已經(jīng)結(jié)束了:

>>> next(g) Traceback (most recent call last):   File "<stdin>", line 1, in <module> StopIteration

因此,我們可以簡(jiǎn)單認(rèn)為 for-in 循環(huán)在 Python 虛擬機(jī)內(nèi)部是這樣實(shí)現(xiàn)的:

  • 不斷調(diào)用 next 函數(shù)讓生成器產(chǎn)出數(shù)據(jù);

  • 直到生成器拋出 StopIteration 異常;

在經(jīng)典的線程模型中,每個(gè)線程有一個(gè)獨(dú)立的執(zhí)行流,只能執(zhí)行一個(gè)任務(wù)。如果一個(gè)程序需要同時(shí)處理多個(gè)任務(wù),可以借助 多進(jìn)程 或者 多線程  技術(shù)。假設(shè)一個(gè)站點(diǎn)需要同時(shí)服務(wù)多個(gè)客戶端連接,可以為每個(gè)連接創(chuàng)建一個(gè)獨(dú)立的線程進(jìn)行處理。

不管線程還是進(jìn)程,切換時(shí)都會(huì)帶來(lái)巨大的開(kāi)銷:用戶態(tài)/內(nèi)核態(tài)切換、執(zhí)行上下文保存和恢復(fù)、CPU緩存刷新等等。因此,用線程或進(jìn)程來(lái)驅(qū)動(dòng)小任務(wù)的執(zhí)行,顯然不是一個(gè)理想的選擇。

那么,除了線程和進(jìn)程,還有其他解決方案嗎?

到此,相信大家對(duì)“生成器Generator的原理及用法”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI