av激情亚洲男人的天堂国语,日韩欧美精品一中文字幕,无码av一区二区三区无码,国产又色又爽又刺激的a片,国产又色又爽又刺激的a片

如何編寫Unix管道風(fēng)格的Python代碼

看過 SICP 就知道,其實(shí)函數(shù)式編程中的map, filter 都可以看作是管道思想的應(yīng)用。但其實(shí)管道的思想不僅可以在函數(shù)式語言中使用,只要語言支持定義函數(shù),有能夠存放一組數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu),就可以使用管道的思想。

創(chuàng)新互聯(lián)網(wǎng)站建設(shè)提供從項(xiàng)目策劃、軟件開發(fā),軟件安全維護(hù)、網(wǎng)站優(yōu)化(SEO)、網(wǎng)站分析、效果評(píng)估等整套的建站服務(wù),主營業(yè)務(wù)為成都網(wǎng)站建設(shè)、網(wǎng)站制作,重慶APP軟件開發(fā)以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠的服務(wù)。創(chuàng)新互聯(lián)深信只要達(dá)到每一位用戶的要求,就會(huì)得到認(rèn)可,從而選擇與我們長期合作。這樣,我們也可以走得更遠(yuǎn)!

一個(gè)日志處理任務(wù)

應(yīng)用場景如下:

◆ 某個(gè)目錄及子目錄下有一些 web 服務(wù)器的日志文件,日志文件名以 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 -

其中***一列數(shù)字為發(fā)送的字節(jié)數(shù),若為 ‘-’ 則表示沒有發(fā)送數(shù)據(jù)

◆目標(biāo)是算出總共發(fā)送了多少字節(jié)的數(shù)據(jù),實(shí)際上也就是要把日志記錄的沒一行的***一列數(shù)值加起來

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

問題并不復(fù)雜,幾個(gè) for 循環(huán)就能搞定:

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

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

然而,設(shè)想以后有了新的統(tǒng)計(jì)任務(wù),比如:

1.統(tǒng)計(jì)某個(gè)特定頁面的訪問次數(shù)

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

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

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

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

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

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 對(duì) closure 中的變量不能進(jìn)行賦值操作,
# 因此這里只能使用全局變量
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 的設(shè)計(jì)并不好。它除了尋找文件以外還調(diào)用了日志文件處理函數(shù),因此在其他任務(wù)中很可能就無法使用。另外 add_count 的參數(shù)必須是 file like object,因此測(cè)試時(shí)不能簡單的直接使用字符串。

#p#

管道風(fēng)格的程序

下面考慮用 Unix 的工具和管道我們會(huì)如何完成這個(gè)任務(wù):

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

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

我們可以在 python 代碼中模擬這些工具,Unix 的工具通過文本來傳遞結(jié)果,在 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 這三個(gè)函數(shù),只需要連續(xù)調(diào)用就可以像 Unix 的管道一樣將這些函數(shù)組合起來。數(shù)據(jù)在管道中的變化如下圖(簡潔起見,過濾器直接標(biāo)在箭頭上 ):

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


網(wǎng)站名稱:如何編寫Unix管道風(fēng)格的Python代碼
標(biāo)題鏈接:http://uogjgqi.cn/article/ccshhoe.html
掃二維碼與項(xiàng)目經(jīng)理溝通

我們?cè)谖⑿派?4小時(shí)期待你的聲音

解答本文疑問/技術(shù)咨詢/運(yùn)營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流