Python 可迭代的對象、迭代器 和生成器(Sentence類第3版:生成器函數)

Sentence類第3版:生成器函數

實現相同功能,但卻符合 Python 習慣的方式是,用生成器函數代替
SentenceIterator 類。先看示例 14-5,然后詳細說明生成器函數。
示例 14-5 sentence_gen.py:使用生成器函數實現 Sentence 類

import re
import reprlib
RE_WORD = re.compile('\w+')
class Sentence:def __init__(self, text):self.text = textself.words = RE_WORD.findall(text)def __repr__(self):return 'Sentence(%s)' % reprlib.repr(self.text)def __iter__(self):for word in self.words: ?yield word ?return ?
# 完成! ?

? 迭代 self.words。
? 產出當前的 word。
? 這個 return 語句不是必要的;這個函數可以直接“落空”,自動返
回。不管有沒有 return 語句,生成器函數都不會拋出 StopIteration
異常,而是在生成完全部值之后會直接退出。

? 不用再單獨定義一個迭代器類!
我們又使用一種不同的方式實現了 Sentence 類,而且也能通過示例
14-2 中的測試。
在示例 14-4 定義的 Sentence 類中,__iter__ 方法調用
SentenceIterator 類的構造方法創建一個迭代器并將其返回。而在示
例 14-5 中,迭代器其實是生成器對象,每次調用 __iter__ 方法都會
自動創建,因為這里的 __iter__ 方法是生成器函數。
下面全面說明生成器函數。

生成器函數的工作原理

只要 Python 函數的定義體中有 yield 關鍵字,該函數就是生成器函
數。調用生成器函數時,會返回一個生成器對象。也就是說,生成器函
數是生成器工廠。

普通的函數與生成器函數在句法上唯一的區別是,在后者的
定義體中有 yield 關鍵字。有些人認為定義生成器函數應該使用
一個新的關鍵字,例如 gen,而不該使用 def,但是 Guido 不同
意。他的理由參見“PEP 255—Simple
Generators”(https://www.python.org/dev/peps/pep-0255/)。

下面以一個特別簡單的函數說明生成器的行為

>>> def gen_123(): # ?
... yield 1 # ?
... yield 2
... yield 3
...
>>> gen_123 # doctest: +ELLIPSIS
<function gen_123 at 0x...> # ?
>>> gen_123() # doctest: +ELLIPSIS
<generator object gen_123 at 0x...> # ?
>>> for i in gen_123(): # ?
... print(i)
123 >>> g
=
gen_123() #
?
>>> next(g) # ?
1 >>> next(g)
2 >>> next(g)
3 >>> next(g) #
?
Traceback (most recent call last):
...
StopIteration

? 只要 Python 函數中包含關鍵字 yield,該函數就是生成器函數。
? 生成器函數的定義體中通常都有循環,不過這不是必要條件;這里
我重復使用 3 次 yield。
? 仔細看,gen_123 是函數對象。
? 但是調用時,gen_123() 返回一個生成器對象。
? 生成器是迭代器,會生成傳給 yield 關鍵字的表達式的值。
? 為了仔細檢查,我們把生成器對象賦值給 g。
? 因為 g 是迭代器,所以調用 next(g) 會獲取 yield 生成的下一個元
素。
? 生成器函數的定義體執行完畢后,生成器對象會拋出
StopIteration 異常。

生成器函數會創建一個生成器對象,包裝生成器函數的定義體。把生成
器傳給 next(…) 函數時,生成器函數會向前,執行函數定義體中的
下一個 yield 語句,返回產出的值,并在函數定義體的當前位置暫
停。最終,函數的定義體返回時,外層的生成器對象會拋出
StopIteration 異常——這一點與迭代器協議一致。

我覺得,使用準確的詞語描述從生成器中獲取結果的過程,
有助于理解生成器。注意,我說的是產出或生成值。如果說生成
器“返回”值,就會讓人難以理解。函數返回值;調用生成器函數返
回生成器;生成器產出或生成值。生成器不會以常規的方式“返
回”值:生成器函數定義體中的 return 語句會觸發生成器對象拋
出 StopIteration 異常。

示例 14-6 使用 for 循環更清楚地說明了生成器函數定義體的執行過
程。

示例 14-6 運行時打印消息的生成器函數

>>> def gen_AB(): # ?
... print('start')
... yield 'A' # ?
... print('continue')
... yield 'B' # ?
... print('end.') # ?
...
>>> for c in gen_AB(): # ?
... print('-->', c) # ?
...
start ?
--> A ?
continue ?
--> B ?
end. ?
>>> ?

? 定義生成器函數的方式與普通的函數無異,只不過要使用 yield 關鍵字。
? 在 for 循環中第一次隱式調用 next() 函數時(序號?),會打印
‘start’,然后停在第一個 yield 語句,生成值 ‘A’。
? 在 for 循環中第二次隱式調用 next() 函數時,會打印
‘continue’,然后停在第二個 yield 語句,生成值 ‘B’。
? 第三次調用 next() 函數時,會打印 ‘end.’,然后到達函數定義體
的末尾,導致生成器對象拋出 StopIteration 異常。
? 迭代時,for 機制的作用與 g = iter(gen_AB()) 一樣,用于獲取
生成器對象,然后每次迭代時調用 next(g)。
? 循環塊打印 --> 和 next(g) 返回的值。但是,生成器函數中的
print 函數輸出結果之后才會看到這個輸出。
? ‘start’ 是生成器函數定義體中 print(‘start’) 輸出的結果。
? 生成器函數定義體中的 yield ‘A’ 語句會生成值 A,提供給 for 循
環使用,而 A 會賦值給變量 c,最終輸出 --> A。
? 第二次調用 next(g),繼續迭代,生成器函數定義體中的代碼由
yield ‘A’ 前進到 yield ‘B’。文本 continue 是由生成器函數定義
體中的第二個 print 函數輸出的。
? yield ‘B’ 語句生成值 B,提供給 for 循環使用,而 B 會賦值給變
量 c,所以循環打印出 --> B。
? 第三次調用 next(it),繼續迭代,前進到生成器函數的末尾。文本
end. 是由生成器函數定義體中的第三個 print 函數輸出的。到達生成
器函數定義體的末尾時,生成器對象拋出 StopIteration 異常。for
機制會捕獲異常,因此循環終止時沒有報錯。
? 現在,希望你已經知道示例 14-5 中 Sentence.__iter__ 方法的作
用了:__iter__ 方法是生成器函數,調用時會構建一個實現了迭代器
接口的生成器對象,因此不用再定義 SentenceIterator 類了。這一版 Sentence 類比前一版簡短多了,但是還不夠懶惰。如今,人們
認為惰性是好的特質,至少在編程語言和 API 中是如此。惰性實現是指
盡可能延后生成值。這樣做能節省內存,而且或許還可以避免做無用的
處理。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/911869.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/911869.shtml
英文地址,請注明出處:http://en.pswp.cn/news/911869.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

5G自協商

好的&#xff0c;下面是一個基于裸機 C 環境的自協商實現示例代碼&#xff0c;支持 **最高 5G 并向下兼容**。這個代碼框架假設你使用的是 IEEE 802.3 規范下的 **MDIO** 接口和常見的 **Marvell PHY**&#xff08;或類似支持 5G/2.5G 的PHY&#xff09;。 c #include <std…

sublime 4200 激活

目錄 下載激活方式一&#xff1a;sublime 打開方式二&#xff1a;https://hexed.it 打開 下載 sublime官方下載 sublime_text_build_4200_x64.zip 激活 方式一&#xff1a;sublime 打開 1、復制 sublime_text.exe 為 sublime_text_activation.exe 2、直接使用 sublime_ 打開…

Ceph 和 MinIO

Ceph 和 MinIO 是兩種主流的分布式存儲系統&#xff0c;但它們的設計目標、架構和使用場景存在顯著差異。以下是清晰的對比解析&#xff1a; &#x1f9e9; 核心定位對比 維度CephMinIO定位統一存儲平臺&#xff08;塊/對象/文件&#xff09;純對象存儲&#xff08;S3兼容&…

cili3d筆記20 正交投影3d重建筆記1

正交視圖轉3d mostFrequentCluster.lines.forEach(line > {const [x1, y1, x2, y2] line;let xhat{x1,x2};let yhat{y1,y2};}); 沒考慮到側視圖 const clusters clusterLines(inputlines, 5);const lines3d:[number,number,number,number,number,number][][]const { mostM…

【Docker基礎】Docker容器生命周期管理:從創建到刪除的完整指南

目錄 1 容器生命周期概述 2 容器創建&#xff08;docker create&#xff09; 2.1 docker create命令詳解 2.2 創建流程解析 2.3 創建與運行的區別 3 容器啟動&#xff08;docker start&#xff09; 3.1 docker start命令詳解 3.2 啟動流程解析 3.3 啟動與運行的區別 …

Docker、Docker composer與Docker desktop

文章目錄 Docker、Docker composer與Docker desktop一、docker、docker composer、docker desktop1.1 Docker1.2 Docker Compose1.3 Docker Desktop1.4 三者之間的區別 二、docker desktop的安裝和換源2.1 前期準備WSL2 2.1 Docker Desktop 安裝下載 Docker Desktop安裝 Docker…

H5錄音、圖文視頻IndexDB儲存最佳實踐:用AI生成語音備忘錄

引言 早在大學的時候&#xff0c;我就期望做一款屬于自己的 APP&#xff0c;可惜那時不懂技術。現在有了技術&#xff0c;但卻沒有時間。好在 AI 的快速發展終于讓我完成了這個愿望。于是&#xff0c;我用半天的時間&#xff0c;用 AI 生成了一個純前端的 H5 程序&#xff1a;…

簡述C++ nlohmann/json 庫

目錄 JSON概述 nlohmann/json 庫的使用 創建json數組/對象 字符串解析&#xff08;parse反序列化&#xff09; 數據訪問 序列化 文件讀寫 JSON概述 JSON(JavaScrip Object Notation)是一種輕量級、跨語言的數據交換格式。它基于 ECMAScript 子集&#xff0c;以獨立于編程…

定制開發開源AI智能名片與S2B2C商城小程序的內容分發體系構建:基于“1+N“素材復用模型的創新實踐

摘要&#xff1a;在數字內容爆炸式增長的當下&#xff0c;本文針對內容分發效率低下的行業痛點&#xff0c;提出基于"定制開發開源AI智能名片S2B2C商城小程序"的一體化解決方案。通過構建"1篇長文10條長視頻20條短視頻10個平臺"的素材復用公式&#xff0c;…

c++26新功能—hive容器

一、容器的演進 科學進步的過程一般來說都是從先解決常用的、迫切的問題開始&#xff0c;然后再逐步解決一些少見不迫切的問題&#xff0c;直到最終解決到認知程度內的諸多問題。舉一個網上的例子&#xff0c;以前說咱們無法生產水筆的尖頭上的鋼球&#xff0c;其實這對于國內…

Kafka 源碼剖析:消息存儲與協議實現(二)

四、協議實現機制探秘 4.1 生產者協議 4.1.1 消息發送流程 Producer 在向 Kafka 集群發送消息時&#xff0c;首先會根據分區策略選擇目標分區 。常見的分區策略有輪詢、按消息鍵的哈希值分區以及自定義分區策略 。如果生產者在發送消息時指定了分區號&#xff0c;那么消息就…

Vue.js 與 TypeScript:最佳實踐

1. 引言 Vue.js 是一個漸進式、靈活的 JavaScript 框架&#xff0c;廣泛用于構建用戶界面和單頁應用&#xff08;SPA&#xff09;。而 TypeScript 是 JavaScript 的一個超集&#xff0c;添加了靜態類型和其他高級特性。將兩者結合使用&#xff0c;可以幫助開發者構建更具可維護…

webpack5 css-loader:從基礎到原理

webpack 處理樣式 webpack本身是不能識別樣式資源的&#xff0c;需要借助Loader來幫助webpack解析樣式資源&#xff0c;樣式資源包括但不限于css/less/sass/scss/styl 未使用樣式處理加載器前 運行webpack打包命令 bash npx webpack報錯信息如圖&#xff0c;提示無法識別css…

【GESP】C++三級練習 luogu-B2096 直方圖

GESP C三級練習&#xff0c;一維數組練習&#xff0c;難度★★☆☆☆。 題目題解詳見&#xff1a;【GESP】C三級練習 luogu-B2096 直方圖 | https://www.coderli.com/gesp-3-luogu-b2096/ 【GESP】C三級練習 luogu-B2096 直方圖 | OneCoderGESP C三級練習&#xff0c;一維數組…

【網站內容安全檢測】之2:從網站所有URL頁面中提取所有外部及內部域名信息

還沒寫成Go的&#xff0c;用Python吧&#xff0c;稍微慢一點 依賴內容&#xff08;安裝命令pip install -r requirements.txt) requirements.txt aiohttp beautifulsoup44.12.2 tqdm4.66.1 redis5.2.1 motor3.3.1 pymongo4.6.0 chardet提取域名的程序 domain_extractor.py …

【LLaMA-Factory 實戰系列】四、API 篇 - 部署推理服務與批量調用實戰

【LLaMA-Factory 實戰系列】四、API 篇 - 部署推理服務與批量調用實戰 1. 引言2. 推理后端的選擇與對比3. 部署 API 推理服務3.1 創建 API 配置文件3.2 啟動 API 服務3.3 探索交互式 API 文檔 4. 編寫 Python 腳本進行批量調用4.1 準備工作4.2 批量調用腳本4.3 運行腳本并查看結…

C++工廠模式的作用(工廠方法、Factory Method、Factory Pattern)

文章目錄 代碼示例工廠的作用1. 對象創建的封裝 &#x1f3ed;2. 解耦客戶端和具體類 &#x1f517;3. 統一的創建入口 &#x1f6aa;4. 隱藏實現細節 &#x1f3ad; 在這個項目中的具體體現總結 代碼示例 https://gitee.com/arnold_s/my-learning-test/tree/master/20250610_…

9-C#修改任務管理的名稱

C#修改任務管理的名稱

Fisco Bcos學習 - 搭建第一個區塊鏈網絡

文章目錄 一、前言二、環境準備三、安裝依賴在 macOS 上安裝依賴在 Ubuntu 上安裝依賴在 CentOS 上安裝依賴 四、創建操作目錄并下載安裝腳本五、搭建單群組 4 節點聯盟鏈六、啟動 FISCO BCOS 鏈七、檢查進程八、檢查日志輸出 在數字化時代&#xff0c;區塊鏈技術正逐漸成為推動…

可視化圖解算法53:表達式求值

牛客網 面試筆試 TOP 101 1. 題目 描述 請寫一個整數計算器&#xff0c;支持加減乘三種運算和括號。 數據范圍&#xff1a;0≤∣s∣≤100&#xff0c;保證計算結果始終在整型范圍內 要求&#xff1a;空間復雜度&#xff1a; O(n)&#xff0c;時間復雜度 O(n) 示例1 輸入…