《Python Cookbook 3rd》筆記(4.13):建立資料處理管道
建立資料處理管道
問題
你想以資料管道 (類似 Unix 管道) 的方式迭代處理資料。比如,你有個大量的資料需要處理,但是不能將它們一次性放入記憶體中。
解法
生成器函式是一個實現管道機制的好辦法。為了演示,假定你要處理一個非常大的日誌檔案目錄:
foo/
access-log-012007.gz
access-log-022007.gz
access-log-032007.gz
...
access-log-012008
bar/
access-log-092007.bz2
...
access-log-022008
假設每個日誌檔案包含這樣的資料:
124.115.6.12 - - [10/Jul/2012:00:18:50 -0500] "GET /robots.txt ..." 200 71
210.212.209.67 - - [10/Jul/2012:00:18:51 -0500] "GET /ply/ ..." 200 11875
210.212.209.67 - - [10/Jul/2012:00:18:51 -0500] "GET /favicon.ico ..." 404 369
61.135.216.105 - - [10/Jul/2012:00:20:04 -0500] "GET /blog/atom.xml ..." 304 -
...
為了處理這些檔案,你可以定義一個由多個執行特定任務獨立任務的簡單生成器函式組成的容器。就像這樣:
import os
import fnmatch
import gzip
import bz2
import re
def gen_find(filepat, top):
'''
Find all filenames in a directory tree that match a shell wildcard pattern
'''
for path, dirlist, filelist in os.walk(top):
for name in fnmatch.filter(filelist, filepat):
yield os.path.join(path,name)
def gen_opener(filenames):
'''
Open a sequence of filenames one at a time producing a file object.
The file is closed immediately when proceeding to the next iteration.
'''
for filename in filenames:
if filename.endswith('.gz'):
f = gzip.open(filename, 'rt')
elif filename.endswith('.bz2'):
f = bz2.open(filename, 'rt')
else:
f = open(filename, 'rt')
yield f
f.close()
def gen_concatenate(iterators):
'''
Chain a sequence of iterators together into a single sequence.
'''
for it in iterators:
yield from it
def gen_grep(pattern, lines):
'''
Look for a regex pattern in a sequence of lines
'''
pat = re.compile(pattern)
for line in lines:
if pat.search(line):
yield line
現在你可以很容易的將這些函式連起來建立一個處理管道。比如,為了查詢包含單詞 python 的所有日誌行,你可以這樣做:
lognames = gen_find('access-log*', 'www')
files = gen_opener(lognames)
lines = gen_concatenate(files)
pylines = gen_grep('(?i)python', lines)
for line in pylines:
print(line)
如果將來的時候你想擴充套件管道,你甚至可以在生成器表示式中包裝資料。比如,下面這個版本計算出傳輸的位元組數並計算其總和。
lognames = gen_find('access-log*', 'www')
files = gen_opener(lognames)
lines = gen_concatenate(files)
pylines = gen_grep('(?i)python', lines)
bytecolumn = (line.rsplit(None,1)[1] for line in pylines)
bytes = (int(x) for x in bytecolumn if x != '-')
print('Total', sum(bytes))
討論
以管道方式處理資料可以用來解決各類其他問題,包括解析,讀取實時資料,定時輪詢等。
為了理解上述程式碼,重點是要明白 yield 語句作為資料的生產者而 for 迴圈語句作為資料的消費者。當這些生成器被連在一起後,每個 yield 會將一個單獨的資料元素傳遞給迭代處理管道的下一階段。在例子最後部分, sum() 函式是最終的程式驅動者,每次從生成器管道中提取出一個元素。
這種方式一個非常好的特點是每個生成器函式很小並且都是獨立的。這樣的話就很容易編寫和維護它們了。很多時候,這些函式如果比較通用的話可以在其他場景重複使用。並且最終將這些元件組合起來的程式碼看上去非常簡單,也很容易理解。
使用這種方式的記憶體效率也不得不提。上述程式碼即便是在一個超大型檔案目錄中也能工作的很好。事實上,由於使用了迭代方式處理,程式碼執行過程中只需要很小很小的記憶體。
在呼叫 gen concatenate() 函式的時候你可能會有些不太明白。這個函式的目的是將輸入序列拼接成一個很長的行序列。 itertools.chain() 函式同樣有類似的功能,但是它需要將所有可迭代物件最為引數傳入。在上面這個例子中,你可能會寫類似這樣的語句 lines = itertools.chain(*files) ,使得 gen_opener() 生成器能被全部消費掉。但由於 gen_opener() 生成器每次生成一個開啟過的檔案,等到下一個迭代步驟時檔案就關閉了,因此 china() 在這裡不能這樣使用。上面的方案可以避免這種情況。
gen_concatenate() 函式中出現過 yield from 語句,它將 yield 操作代理到父生成器上去。語句 yield from it 簡單的返回生成器 it 所產生的所有值。關於這個我們在 4.14 小節會有更進一步的描述。
最後還有一點需要注意的是,管道方式並不是萬能的。有時候你想立即處理所有資料。然而,即便是這種情況,使用生成器管道也可以將這類問題從邏輯上變為工作流的處理方式。
David Beazley 在他的 Generator Tricks for Systems Programmers 教程中對於這種技術有非常深入的講解。可以參考這個教程獲取更多的資訊。
相關文章
- 《Python Cookbook 3rd》筆記(5.17):將位元組寫入文字檔案Python筆記
- 《Python資料處理》讀書筆記Python筆記
- 機器學習筆記---資料預處理機器學習筆記
- JSP筆記-XML 資料處理JS筆記XML
- Python深度學習(處理文字資料)--學習筆記(十二)Python深度學習筆記
- Python資料處理(二):處理 Excel 資料PythonExcel
- 《Eloquent JavaScript 3rd》筆記JavaScript筆記
- Python筆記(五)——檔案處理Python筆記
- python 處理資料Python
- YOLOv3學習筆記之資料處理YOLO筆記
- SpringMVC 學習筆記(四) 處理模型資料SpringMVC筆記模型
- Python檔案處理-專題筆記Python筆記
- Kafka聯結器建立資料管道Kafka
- 機器學習演算法筆記之6:資料預處理機器學習演算法筆記
- 維度處理-資料倉儲-讀書筆記(四)筆記
- 【Pandas學習筆記02】-資料處理高階用法筆記
- 【Pandas學習筆記02】處理資料實用操作筆記
- 《Spring MVC CookBook》讀書筆記SpringMVC筆記
- python筆記-文字處理(第三天)Python筆記
- 4, 手工建立資料庫(筆記)資料庫筆記
- [資料處理]python基礎Python
- Python資料處理-pandas用法Python
- Python資料處理典型用法Python
- python cookbookPython
- 【筆記】基於Python的數字影象處理筆記Python
- 請求處理管道個人理解
- Python資料處理(一):處理 JSON、XML、CSV 三種格式資料PythonJSONXML
- 達夢資料庫日常管理之問題處理筆記1資料庫筆記
- 【大資料】離線批處理計算MapReduce | 複習筆記大資料筆記
- Python文字資料分析與處理Python
- Python使用xlrd處理excel資料PythonExcel
- 自然語言處理常用資源筆記分享自然語言處理筆記
- java異常處理筆記Java筆記
- Laravel請求處理管道理解Laravel
- 【R資料科學讀書筆記】R語言中的管道操作資料科學筆記R語言
- python筆記--資料型別Python筆記資料型別
- Python資料分析 DataFrame 筆記Python筆記
- Python資料分析 numpy 筆記Python筆記