Python 中的生成器趣味實(shí)踐
1. 遍歷文本文件中的單詞
假設(shè)存在文本文件 test.txt,內(nèi)容如下:
The Zen of Python
Beautiful is better than ugly
Simple is better than complex
注意文件包含有空行,要求完成如下任務(wù):
- 統(tǒng)計(jì)文件有多少個(gè)單詞
- 統(tǒng)計(jì)文件中每個(gè)單詞出現(xiàn)的頻率
2. 直接遍歷的方法
請(qǐng)參考詞條 “Python 中的迭代器趣味實(shí)踐” 的第 2 小節(jié),通過(guò)直接遍歷文件中單詞的方式實(shí)現(xiàn) “統(tǒng)計(jì)單詞的個(gè)數(shù)” 和 “統(tǒng)計(jì)單詞的出現(xiàn)頻率”。
2.1 優(yōu)點(diǎn)
直接遍歷的方式的優(yōu)點(diǎn)在于代碼簡(jiǎn)單,框架代碼如下:
file = open('test.txt')
while True:
line = file.readline()
if not line:
break
words = line.split()
for word in words:
處理 word
- 在第 4 行,讀取文件的每一行
- 在第 8 行,將文件的一行分割為多個(gè)單詞
- 在第 10 行,對(duì)當(dāng)前正在遍歷的單詞進(jìn)行處理
2.2 缺點(diǎn)
直接遍歷的方式的缺點(diǎn)在于代碼重復(fù),實(shí)現(xiàn) “統(tǒng)計(jì)單詞個(gè)數(shù)” 和 “統(tǒng)計(jì)單詞出現(xiàn)頻率” 這兩個(gè)功能需求時(shí),遍歷單詞的框架代碼是重復(fù)的。
3. 基于迭代器的方法
請(qǐng)參考詞條 “Python 中的迭代器趣味實(shí)踐” 的第 3 小節(jié)和第 4 小節(jié),通過(guò)基于迭代器的方式實(shí)現(xiàn) “統(tǒng)計(jì)單詞的個(gè)數(shù)” 和 “統(tǒng)計(jì)單詞的出現(xiàn)頻率”。
3.1 優(yōu)點(diǎn)
使用迭代器的方式的優(yōu)點(diǎn)在于遍歷單詞的代碼簡(jiǎn)單,使用如下代碼:
for word in IterateWord(file):
處理 word
即可對(duì)文件中所有的單詞進(jìn)行遍歷。
3.2 缺點(diǎn)
使用迭代器的方式的缺點(diǎn)在于迭代器的實(shí)現(xiàn)較為復(fù)雜,相比之下,直接遍歷的框架代碼則非常簡(jiǎn)單直觀。在下面的小節(jié)中,我們基于生成器簡(jiǎn)化迭代器的實(shí)現(xiàn)。
4. 基于生成器的方法
4.1 實(shí)現(xiàn)生成器
本小節(jié)使用生成器實(shí)現(xiàn)遍歷文件中所有的單詞,代碼如下:
def generateWord(file):
while True:
line = file.readline()
if not line:
break
words = line.split()
for word in words:
yield word
- 在第 1 行,定義生成器函數(shù) generateWord,遍歷文件 file 中的單詞
- 在第 3 行,讀取文件的一行
- 在第 4 行,如果 not line 為真,則表示讀取文件結(jié)束,使用 break 退出
- 在第 7 行,把 line 切割為多個(gè)單詞
- 在第 8 行,遍歷列表 words
- 在第 9 行,使用 yield 關(guān)鍵字返回當(dāng)前正在遍歷的單詞
4.2 統(tǒng)計(jì)單詞的個(gè)數(shù)
file = open('test.txt')
count = 0
for word in generateWord(file):
print(word)
count = count + 1
- 在第 1 行,打開(kāi)文件 test.txt
- 在第 2 行,變量 count 用于記錄文件中單詞的個(gè)數(shù)
- 在第 4 行,遍歷文件中的每一個(gè)單詞
- 在第 5 行,打印當(dāng)前遍歷的單詞
- 在第 6 行,統(tǒng)計(jì)單詞個(gè)數(shù)
程序運(yùn)行輸出結(jié)果如下:
The
Zen
of
Python
Beautiful
is
better
than
ugly
Simple
is
better
than
complex
count = 14
4.3 統(tǒng)計(jì)單詞的出現(xiàn)頻率
file = open('test.txt')
dict = {}
for word in generateWord(file):
if word in dict:
dict[word] += 1
else:
dict[word] = 1
for word,count in dict.items():
print('%s: %d' % (word, count))
- 在第 1 行,打開(kāi)文件 test.txt,變量 file 標(biāo)識(shí)已經(jīng)打開(kāi)的文件
- 在第 4 行,遍歷每一行文本的單詞
- 在第 5 行,如果 word 已經(jīng)存在于 dict 中
- 則在第 5 行,該單詞出現(xiàn)的次數(shù)加 1
- 在第 7 行,如果 word 不存在于 dict 中
- 則在第 8 行,該單詞出現(xiàn)的次數(shù)初始化為 1
- 在第 5 行,如果 word 已經(jīng)存在于 dict 中
- 在第 10 行,打印 dict 的鍵和值
程序運(yùn)行輸出結(jié)果如下:
The: 1
Zen: 1
of: 1
Python: 1
Beautiful: 1
is: 2
better: 2
than: 2
ugly: 1
Simple: 1
complex: 1
結(jié)果表明:
- 單詞 is better than 出現(xiàn)了 2 次
- 其它單詞出現(xiàn)了 1 次
4.4 總結(jié)
與 “直接遍歷” 和 “通過(guò)迭代器遍歷” 這兩種方式相比,基于生成器的方法由如下優(yōu)點(diǎn):
4.4.1 實(shí)現(xiàn)生成器簡(jiǎn)單
實(shí)現(xiàn)生成器的函數(shù) generateWord 的邏輯簡(jiǎn)單直觀,代碼如下:
def generateWord(file):
while True:
line = file.readline()
if not line:
break
words = line.split()
for word in words:
yield word
- 首先,函數(shù)依次讀取文件的每一行
- 然后,再把讀取的行切割成單詞
- 最后,遍歷單詞
4.4.2 使用生成器簡(jiǎn)單
通過(guò) for 循環(huán)即可遍歷文件中的單詞,generateWord 隱藏了各種實(shí)現(xiàn)細(xì)節(jié),代碼如下:
for word in generateWord(file):
處理 word