深夜Python - 第1夜 - for 迷 in 迷思 在一個月黑風高的夜晚,我悄悄打開編輯器,進入程式的世界。剛剛學會Python的我,由於一段時間的過度裝B,被委托優化一段程式,我信心十足地接下來,看了又看……這不挺好的程式嗎?但是又覺得哪不太對,無奈,只好去找夜貓兄。 “夜貓兄!速救!——” ...
深夜Python - 第1夜 - for 迷 in 迷思
在一個月黑風高的夜晚,我悄悄打開編輯器,進入程式的世界。剛剛學會Python的我,由於一段時間的過度裝B,被委托優化一段程式,我信心十足地接下來,看了又看……這不挺好的程式嗎?但是又覺得哪不太對,無奈,只好去找夜貓兄。
“夜貓兄!速救!——”我敲門敲出了過年放煙花般的氛圍。夜貓兄剛剛起床,瞅瞅我的程式,然後瞅瞅我,一臉鄙夷:“這……是你寫的?”
“這是……其實是β兄的原創……”我感覺不妙……
“真差!”夜貓兄只說了這2個字。
“啥啥啥?”我滿臉問號。上貢了十袋小魚乾,三杯熱牛奶,終於讓夜貓兄滿意,同意傳授我Python秘籍。夜貓兄親自上手,帶著我把代碼優化了一遍。
優化的位置很多,一段一段來看。
1 testdata = np.zeros((1, 80, 30)) ### 1 80 36 2 for i in range(80): ## 80 3 for j in range(30): 4 testdata[0, i, j] = m[i, j]
這可以看成一段C語言里初始化數組的程式,其中np為numpy庫,m為80×30的數組,testdata用於數據分類,必須增加一個維度,所以有了上面的程式,它類似於如下C語言代碼:
1 int testdata[1][80][30] = {0}; 2 int i,j; 3 for(i=0; i<80; i++){ 4 for(j=0; j<30; j++){ 5 testdata[0][i][j] = m[i][j]; 6 } 7 }
“夜貓兄,這不就是C語言的改寫嗎?有什麼問題嗎?”
“Python的優勢就是它語法很簡潔,開發起來很高效,所以用Python模仿C開發就很搞笑。看我給你重寫這段代碼。”
還沒等我反應過來,夜貓兄的爪子就敲完了鍵盤……我一看,啥啥啥?這就行了?
1 testdata = m.reshape((1, 80, 30))
“reshape是numpy自帶的方法,可以重新組織數據,通俗點說,改變數組的形狀。numpy底層是C語言實現的,所以速度比用Python的for快得多,而且代碼簡潔易讀,這麼寫都不用加註釋了。”
“對對對,夜貓兄威武!”
“多說一句,註意reshape函數是有別的參數可以用的,就是order。預設order='C',就是上面的效果,order='F'就會按照列的順序排列數據,還有個'A',具體的去看官方文檔。給你演示一下。”
1 >>> a = np.arange(12) 2 >>> a.reshape((4,3)) 3 array([[ 0, 1, 2], 4 [ 3, 4, 5], 5 [ 6, 7, 8], 6 [ 9, 10, 11]]) 7 >>> a.reshape((4,3), order='C') 8 array([[ 0, 1, 2], 9 [ 3, 4, 5], 10 [ 6, 7, 8], 11 [ 9, 10, 11]]) 12 >>> a.reshape((4,3), order='F') 13 array([[ 0, 4, 8], 14 [ 1, 5, 9], 15 [ 2, 6, 10], 16 [ 3, 7, 11]])
"哇,學到了學到了。"我笑嘻嘻地搓著手,“誒,那下麵那段……”
“對,類似的。”夜貓兄捻起一條小魚乾,嘬了一口牛奶,改起了下麵的代碼:
1 tdata = np.zeros((47, 4)) 2 ... 3 data = tctimeClient.recv(47 * 4 * 4) # 40ms 4位元組 4 ptr = 0 5 for i in range(47 * 4): 6 tdata[ptr % 47][ptr // 47] = struct.unpack('f', data[4 * i:4 * i + 4])[0] # / 浮點數除,//整除 7 ptr += 1
這段代碼中data是接收到的位元組數據,數據類型需要轉換成float32,所以需要用struct修改數據類型,類似於C語言的強制類型轉換。當然聰明如我——夜貓兄的高手在C語言里會用union(共用體)來實現類型的轉換。會用C語言的童鞋可以看出,tdata[ptr % 47][ptr // 47]就是按照列的順序排列數據。但是如夜貓兄所說,這樣的做法在Python里非常低效的,應該用現成的庫代替。而struct.unpack是可以多位元組操作的,所以應該用47×4個'f'一次性把數據全轉換掉。
1 byte_data = tctimeClient.recv(47 * 4 * 4) # 40ms 4位元組 2 float_data = struct.unpack('f'*47*4, byte_data) 3 tdata = np.array(float_data).reshape((47, 4), order='F')
“夜貓兄,給講講struct唄~”
“自己搜去!”夜貓兄只顧著改代碼,不太願意理我,我只好再掏出來一罐小魚乾……“這是官方文檔,下次自己搜啊。”
……
光陰似箭……牛奶杯漸漸見底……夜貓兄的爪子停了下來,“今天就到這吧,我要睡午覺了,代碼慢慢改吧。”
“哈?你是不是就是想要小魚乾和牛奶?”
“閉嘴,你走!”夜貓兄一口幹了剩下的小魚乾,把罐子扔給我,“垃圾什麼的都帶走啊!”
深夜Python,第1夜,2019.10.16。