如何编写Unix管道风格的Python代码
2010-09-22 11:10:40 来源:WEB开发网 闂傚倸鍊搁崐鎼佸磹閹间礁纾归柟闂寸绾惧綊鏌熼梻瀵割槮缁炬儳缍婇弻鐔兼⒒鐎靛壊妲紒鎯у⒔閹虫捇鈥旈崘顏佸亾閿濆簼绨绘い鎺嬪灪閵囧嫰骞囬姣挎捇鏌熸笟鍨妞ゎ偅绮撳畷鍗炍旈埀顒勭嵁婵犲嫮纾介柛灞捐壘閳ь剛鎳撻~婵嬪Ω閳轰胶鐤呯紓浣割儐椤戞瑩宕ョ€n喗鐓曟い鎰靛亝缁舵氨绱撻崘鈺傜婵﹤顭峰畷鎺戔枎閹搭厽袦婵犵數濮崑鎾绘⒑椤掆偓缁夌敻骞嗛悙鍝勭婵烇綆鍓欐俊鑲╃磼閹邦収娈滈柡灞糕偓鎰佸悑閹肩补鈧尙鏁栧┑鐐村灦閹稿摜绮旈悽绋课﹂柛鏇ㄥ灠閸愨偓濡炪倖鍔﹀鈧繛宀婁邯濮婅櫣绱掑Ο璇茶敿闂佺ǹ娴烽弫璇差嚕婵犳碍鏅插璺猴工瀹撳棝姊虹紒妯哄缂佷焦鎸冲畷鎴﹀箻鐠囧弶宓嶅銈嗘尰缁嬫垶绂嶉悙顒佸弿婵☆垳鍘ф禍楣冩倵濮樼偓瀚�

看过 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 这样的语言真是太方便了。看起来一切都很美好。
赞助商链接