1. 程式人生 > >python列表推導式(列表生成式)的強大之處

python列表推導式(列表生成式)的強大之處

毫無疑問程式設計師的工作是辛苦的,熬夜加班,未知的bug,頻繁變動的需求,老闆奇葩的想法,繁重的開發任務……

然而,仍然有那麼多的人堅守崗位,以便抱怨,一邊沉浸在程式碼的汪洋中

因為當解決一個困擾許久的bug,實現一個不常規的功能,當成功的從一段優化到極致的程式碼中再次優化提升執行效率,得到的滿足感是不可取代的,程式的世界很單純,付出汗水,得到回報

感嘆完畢,作為一個10多年IT從業者,用了差不多6年的java開發,期間也陸續學過或用過javascricpt,nodejs,lisp,perl,php,awk,golang,ruby,看出來了吧,基本上是哪個流行學下哪個,哪個有需要用下哪個。瞎折騰。

然而,他們都是學了忘,用了丟。精力有限,我希望語言足夠簡單,靈活,讓我用最少的學習代價,卻能發揮最大的頭腦創造和解決問題的能力。java是工程語言,強調的是結構化,規律,整體性,他的臃腫讓我除了工作以外,沒有任何慾望使用他。

直到我學了python,他確實很簡單,足夠靈活的同時,又不會令到程式碼失控。他能用java程式碼最多一半的程式碼量解決同樣的問題。

上一個實際的例子,看看他的靈活和強大:

一個需求,從日誌中查詢一個給定的字串,找到後,處理後續的行,拿出其中某些欄位並重新輸出到檔案。

日誌sample可能是這樣:

#2018-03-08 00:12:17,272 [INFO], [xxxxxxxxxxl][Inbound Msg Forwarder Thread for TID R0813] - TRIS Message sent: {R0813180308003004RTST23B26500   317211    V6.39               }
#2018-03-08 00:12:17,273 [INFO], [xxxxxxxxxx][Inbound Msg Forwarder Thread for TID R0813] - sent: <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE RTST SYSTEM "rdsRTST.dtd">
<RTST>
  <tid>R0813</tid>
  <xmlMsgDateTime>2018-03-08 00:30:04 CST</xmlMsgDateTime>
  <msgName>RTST</msgName>
  <block>23B</block>
  <stack>26</stack>
  <group>500</group>
  <termId>0813</termId>
  <termType>3</termType>
  <version>17211</version>
  <activeChnl>  </activeChnl>
  <homeChnl> </homeChnl>
  <interfaceVersion> V6.39              </interfaceVersion>
</RTST>

#2018-03-08 00:12:17,273 [INFO], [xxxxxxxxxx][Inbound Msg Forwarder Thread for TID R0813] - GSS authentication tid=R0813
#2018-03-08 00:12:17,273 [INFO], [xxxxxxxxxx][Inbound Msg Forwarder Thread for TID R0813] - GSS authentication MsgType=RTST
#2018-03-08 00:12:17,273 [INFO], [xxxxxxxxxx][Inbound Msg Forwarder Thread for TID R0813] - GSS authentication time = 1520439137273, 1520427471680, 28800000 => false
#2018-03-08 00:12:17,273 [INFO], [xxxxxxxxxx][Inbound Msg Forwarder Thread for TID R0813] - GSS authentication Entry Name = kerberos
#2018-03-08 00:12:17,331 [INFO], [xxxxxxxxxx][Inbound Msg Forwarder Thread for TID R0813] - received: <?xml version="1.0" encoding="UTF-8"?>

<BTST>

來看看面向過程的常規程式碼方案:

def _parsehhtlog():
    result = {}
    lineflag = 0
    tid = version = ''
    try:
        with open(_logpath + _getYesterday()) as file_object:
            for num, line in enumerate(file_object):
                if re.search("^<RTST>$", line):
                    lineflag = num
                elif re.search("<tid>\w\d\d\d\d</tid>$", line) and lineflag != 0 and num == lineflag + 1:
                    tid = line[7:12]
                elif re.search("<version>\d\d\d\d\d</version>$", line) and lineflag != 0 and num == lineflag + 9:
                    version = line[11:16]
                    result[tid] = version
                    lineflag = 0
                    print("find a record:", tid, version)
    except IOError as err:
        print('IO exception:may be file path is error!')
        print(str(err))
    return result

基本沒有任何優化,程式碼閱讀也很費力。其實找到指定匹配並處理後續行這個操作應該是一個連續的操作,這裡可以用生成式直接一步處理完畢,直接看程式碼:

def _parsehhtlog():
    result, tid = {}, ''
    try:
        with open(_logpath) as file_object:
            results = [[file_object.readline() for i in range(9)] \
                       for line in file_object if re.search("^<RTST>$", line)]
        for value in results:
            if re.search("<tid>\w\d\d\d\d</tid>$", value[0]):
                tid = value[0][7:12]
            if re.search("<version>\d\d\d\d\d</version>$", value[8]):
                result[tid] = value[8][11:16]
            print(tid, result[tid])
    except IOError as err:
        print('IO exception:', str(err))
    return result

這樣是不是直觀了很多,複雜度上下降了很多,使用的變數也減少了,分步驟的處理方式也利於排錯和增加新功能。

當然,也許還有大神可以更加優化;上述程式碼是我用了一週時間利用上班間隙學習python後的成果。那麼大概python確實足夠簡單。像我這樣笨的人也可以學的這麼快和有信心。

再貼一個計算楊輝三角的解決方案:


         / \
        1   1
       / \ / \
      1   2   1
     / \ / \ / \
    1   3   3   1
   / \ / \ / \ / \
  1   4   6   4   1
 / \ / \ / \ / \ / \
1   5   10  10  5   1
l = [1]
while 1:
    print(l)
    l = [1] + [ l[n] + l[n+1] for n in range(len(l)-1) ]  + [1] 
是否足夠直觀,簡潔?