前言
生成器(generator)可以幫我們在傳遞大量數(shù)據(jù)時節(jié)省內(nèi)存。
一般情況下,生成器只能被讀取一次。
但是總有某種情況下,需要對生成器多次讀取。
本文意在提供一種優(yōu)雅的方式解決此類問題。
環(huán)境
python 3.6
正文
當要對一個生成器多次讀值時,存在多種實現(xiàn),比如 lamda。(印象中似乎有移動指針的方法)
但是這種代碼并不優(yōu)雅。
我們可以實現(xiàn)一個 迭代器協(xié)議的容器類。
這里舉一個例子:
一個文件當中,每一行都存著一個數(shù)字,求出每一行數(shù)字的百分比。為了方便,這里拿一個列表來模擬文件。
詳細代碼如下:
# 生成器讀取文件,這里使用列表模擬文件
def read_file_iter(file):
# with open ...
for line in file:
yield int(line)
# 計算百分比,方法體中讀取了兩次生成器。一次是 sum,一次是 for。生成器在 sum 操作后便已經(jīng)空了。
def cal_percent(numbers):
total = sum(numbers)
results = []
for num in numbers:
results.append(num / total * 100)
return results
# 使用容器類實現(xiàn)迭代讀取文件,這里依然使用列表模擬文件,略去打開文件的步驟
class ReadFile():
def __init__(self, data_path):
self.data_path = data_path
# 每次輪詢該對象時,均會生成一個新的生成器
def __iter__(self):
# with open ...
for line in self.data_path:
yield line
if __name__ == "__main__":
numbers = [10, 100, 1000]
# ------------------
# 在需要對生成器多次讀值時,普通的生成器寫法不再合適。
# 可以實現(xiàn)一種 迭代器協(xié)議的容器類 來滿足這種需要對生成器多次讀值的要求。
# 下列 【情況一】 為普通的迭代寫法,【情況二】為實現(xiàn) 迭代器協(xié)議的容器類
# ------------------
# 【情況一】:
# 這里的結(jié)果是空。
# 因為 read_numbers 是一個生成器。
# 在 cal_percent 中 sum 方法和 for 循環(huán)均是對該生成器的讀取。而生成器只能被讀取一次
read_numbers = read_file_iter(numbers)
results = cal_percent(read_numbers)
print(results)
# 【情況二】
# 這里的結(jié)果是正常的。
# read_numbers 僅僅是一個不包含實際數(shù)據(jù)的對象
# 在 cal_percent 中 sum 方法和 for 循環(huán)讀取該對象時,該對象會分別返回兩個獨立的生成器。因此工作正常。
read_numbers = ReadFile(numbers)
results = cal_percent(read_numbers)
print(results)
擴展
無
參考
無