成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

如何編寫Unix管道風格的Python代碼

開發 后端
Python是一種面向對象的解釋性的計算機程序設計語言,也是一種功能強大而完善的通用型語言,已經具有十多年的發展歷史,成熟且穩定。本文中將介紹如何編寫Unix管道風格的Python代碼。

看過 SICP 就知道,其實函數式編程中的map, filter 都可以看作是管道思想的應用。但其實管道的思想不僅可以在函數式語言中使用,只要語言支持定義函數,有能夠存放一組數據的數據結構,就可以使用管道的思想。

一個日志處理任務

應用場景如下:

◆ 某個目錄及子目錄下有一些 web 服務器的日志文件,日志文件名以 access-log 開頭

◆ 日志格式如下

81.107.39.38 - ... "GET /ply/ply.html HTTP/1.1" 200 97238
81.107.39.38 - ... "GET /ply HTTP/1.1" 304 -

其中***一列數字為發送的字節數,若為 ‘-’ 則表示沒有發送數據

◆目標是算出總共發送了多少字節的數據,實際上也就是要把日志記錄的沒一行的***一列數值加起來

我不直接展示如何用 Unix 管道的風格來處理這個問題,而是先給出一些“不那么好”的代碼,指出它們的問題,***再展示管道風格的代碼,并介紹如何使用 generator 來避免效率上的問題。

問題并不復雜,幾個 for 循環就能搞定:

sum = 0
for path, dirlist, filelist in os.walk(top):
    for name in fnmatch.filter(filelist, "access-log*"):
        # 對子目錄中的每個日志文件進行處理
        with open(name) as f:
            for line in f:
                if line[-1] == '-':
                    continue
                else:
                    sum += int(line.rsplit(None, 1)[1])

利用 os.walk 這個問題解決起來很方便,由此也可以看出 python 的 for 語句做遍歷是多么的方便,不需要額外控制循環次數的變量,省去了設置初始值、更新、判斷循環結束條件等工作,相比 C/C++/Java 這樣的語言真是太方便了。看起來一切都很美好。

然而,設想以后有了新的統計任務,比如:

1.統計某個特定頁面的訪問次數

2.處理另外的一些日志文件,日志文件名字以 error-log 開頭

完成這些任務直接拿上面的代碼過來改改就可以了,文件名的 pattern 改一下,處理每個文件的代碼改一下。其實每次任務的處理中,找到特定名字為特定 pattern 的文件的代碼是一樣的,直接修改之前的代碼其實就引入了重復。

如果重復的代碼量很大,我們很自然的會注意到。然而 python 的 for 循環實在太方便了,像這里找文件的代碼一共就兩行,哪怕重寫一遍也不會覺得太麻煩。for 循環的方便使得我們會忽略這樣簡單代碼的重復。然而,再怎么方便好用,for 循環無法重用,只有把它放到函數中才能進行重用。

(先考慮下是你會如何避免這里的代碼的重復。下面馬上出現的代碼并不好,是“誤導性”的代碼,我會在之后再給出“更好”的代碼。)

因此,我們把上面代碼中不變的部分提取成一個通用的函數,可變的部分以參數的形式傳入,得到下面的代碼:

def generic_process(topdir, filepat, processfunc):
    for path, dirlist, filelist in os.walk(top):
        for name in fnmatch.filter(filelist, filepat):
            with open(name) f:
                processfunc(f)
 
sum = 0
# 很遺憾,python 對 closure 中的變量不能進行賦值操作,
# 因此這里只能使用全局變量
def add_count(f):
    global sum
    for line in f:
        if line[-1] == '-':
            continue
        else:
            sum += int(line.rsplit(None, 1)[1])
 
generic_process('logdir', 'access-log*', add_count)

看起來不變和可變的部分分開了,然而 generic_process 的設計并不好。它除了尋找文件以外還調用了日志文件處理函數,因此在其他任務中很可能就無法使用。另外 add_count 的參數必須是 file like object,因此測試時不能簡單的直接使用字符串。

#p#

管道風格的程序

下面考慮用 Unix 的工具和管道我們會如何完成這個任務:

find logdir -name "access-log*" | \
xargs cat | \
grep '[^-]$' | \
awk '{ total += $NF } END { print total }'

find 根據文件名 pattern 找到文件,cat 把所有文件內容合并輸出到 stdout,grep 從 stdin 讀入,過濾掉行末為 ‘-’ 的行,awk 提取每行***一列,將數值相加,***打印出結果。(省掉 cat 是可以的,但這樣一來 grep 就需要直接讀文件而不是只從標準輸入讀。)

我們可以在 python 代碼中模擬這些工具,Unix 的工具通過文本來傳遞結果,在 python 中可以使用 list。

def find(topdir, filepat, processfunc):
    files = []
    for path, dirlist, filelist in os.walk(top):
        for name in fnmatch.filter(filelist, filepat):
            files.append(name)
    return files
 
 def cat(files):
    lines = []
    for file in files:
        with open(file) as f:
            for line in f:
                lines.append(line)
    return lines
 
 def grep(pattern, lines):
    result = []
    import re
    pat = re.compile(pattern)
    for line in lines:
        if pat.search(line):
            result.append(line)
    resurn result
 
lines = grep('[^-]$', cat(find('logdir', 'access-log*')))
col = (line.rsplit(None, 1)[1] for line in lines)
print sum(int(c) for c in col)

有了 find, cat, grep 這三個函數,只需要連續調用就可以像 Unix 的管道一樣將這些函數組合起來。數據在管道中的變化如下圖(簡潔起見,過濾器直接標在箭頭上 ):

看起來現在的代碼行數比最初直接用 for 循環的代碼要多,但現在的代碼就像 Unix 的那些小工具一樣,每一個都更加可能被用到。我們可以把更多常用的 Unix 工具用 Python 來模擬,從而在 Python 代碼中以 Unix 管道的風格來編寫代碼。

【編輯推薦】

  1. AJAX和XmlHttpRequest下的Web開發
  2. Python 3.0 一個巨大的改變
責任編輯:楊鵬飛 來源: Chen Yufei's blog
相關推薦

2010-03-12 11:07:49

Python retu

2010-02-03 13:55:51

Python 代碼

2012-07-11 10:51:37

編程

2023-05-09 12:34:45

Prophecy可視化工具

2021-05-06 11:04:55

GooglePython代碼

2021-03-17 08:00:59

JS語言Javascript

2022-06-07 09:30:35

JavaScript變量名參數

2024-06-24 14:19:48

2009-12-14 17:04:13

Ruby讀寫UNIX命

2024-10-08 05:00:00

PEP 8編碼Python

2014-04-25 09:02:17

LuaLua優化Lua代碼

2013-04-15 09:02:43

JavaScriptJS

2024-03-20 08:00:00

軟件開發Java編程語言

2023-10-10 08:00:00

2021-04-02 12:37:53

RestfulAPI接口架構

2010-02-05 16:49:05

編寫Android 代

2012-03-15 13:36:51

云計算JavaSpring框架

2015-01-28 14:30:31

android代碼

2022-06-27 06:23:23

代碼編程

2021-06-08 09:35:11

Cleaner ReaReact開發React代碼
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 久久国产精品网 | 日韩在线综合 | 亚洲自拍偷拍免费视频 | 欧美日韩国产精品一区 | 日本aⅴ中文字幕 | 日韩乱码在线 | av大片| 五月天国产视频 | 欧美午夜影院 | 亚洲免费在线播放 | 免费国产一区 | 亚洲免费在线 | 欧美日韩大片 | 极品粉嫩国产48尤物在线播放 | 一区二区av| 久久久久久中文字幕 | 欧美精品video | 久久久久国产一区二区三区 | 国产福利在线小视频 | 国产高清在线精品 | 性高朝久久久久久久3小时 av一区二区三区四区 | 久久一级| 久久久视 | 国产91在线播放 | 国产精品美女久久久久aⅴ国产馆 | 久久久人成影片一区二区三区 | 黄色国产大片 | 成年网站在线观看 | 亚洲视频在线一区 | 国产二区三区 | 一级毛片视频 | 一区二区三区小视频 | 久久精品 | 久久精品国产亚洲一区二区三区 | 亚洲国产成人精品久久 | 国产精品国产三级国产aⅴ中文 | 欧美日韩国产在线观看 | 日韩欧美在线观看 | 国产高清一区二区三区 | 在线2区 | 欧美精品乱码久久久久久按摩 |