提升Python程式速度技巧匯總

來源:互聯網
上載者:User

1. Python編程速度技巧

1.1. 最常見

* 一個最常見的速度陷坑(至少是俺在沒看到網上這篇介紹時陷進去

過好些次的) 是: 許多短字串並成長字串時, 大家通常會用:

切換行號顯示

1 shortStrs = [ str0, str1, ..., strN] 

N+1個字串所組成的數列 
3 longStr = '' 
4 for s in shortStrs: longStr += s

因為Python裡字串是不可變的, 所以每次 longStr += s 都是將原 來的 longStr 與 str 拷貝成一個新字串, 再賦給longStr. 隨著 longStr的不斷增長, 所要拷貝的內容越來越長. 最後導至str0被 拷貝N+1次, str1是N次, ... .

那咋辦呢 ? 咱們來看看Skip Montanaro先生的解說: http://musi-cal.mojam.com/~skip/python/fastpython.html 及可參考一下Guido van Rossum本人的:http://www.python.org/doc/essays/list2str.html

1.1.1. 找出速度瓶頸

* 1)首先在大家應先學會怎麼去找出速度瓶頸: Python內建有profile

模組:

切換行號顯示

1 import profile 
2 profile.run ('想要檢查的函數名()')

就會列印出那個函數裡調用了幾次其它函數, 各用了多少時間, 總共用了多少時間等資訊 --- Nice ? 詳請參閱<<庫參考>>中的 profile模組的論述.

當然腦袋笨一點或是聰明一點的, 也可以用time模組中的time() 來顯示系統時間, 減去上次的time()就是與它的間隔秒數了.

1.1.2. 字串相併

* 就頭上的例子而言, 用 :

切換行號顯示

1 longStr =''.join(shortStrs)

立馬搞定, 但如果shortStrs裡面不都是字串, 而包含了些數 字呢 ? 直接用join就會出錯. 不怕, 這樣來:

切換行號顯示

1 shortStrs = [str(s) for s in shortStrs[i]] 
2 longStr = ''.join(shortStrs)

也即先將數列中所有內容都轉化為字串, 再用join.

對少數幾個字串相併, 應避免用: all = str0 + str1 + str2 + str3 而用: all = '%s%s%s%s' % (str0, str1, str2, str3)

1.1.3. 數列排序

* list.sort ()

你可以按特定的函數來: list.sort( 函數 ), 只要這個函數接受 兩參數, 並按特定規則返回1, 0, -1就可以. --- 很方便吧? 但 會大大減慢運行速度. 下面的方法, 俺舉例子來說明可能更容易 明白.

比方說你的數列是 l = ['az', 'by'], 你想以第二個字母來排序. 先取出你的關鍵詞, 並與每個字串組成一個元組: new = map (lambda s: (s[1], s), l )

於是new變成[('z', 'az'), ('y', 'by')], 再把new排一下序: new.sort()

則new就變成 [('y', 'by'), ('z', 'az')], 再返回每個元組中 的第二個字串: sorted = map (lambda t: t[1], new)

於是sorted 就是: ['by', 'az']了. 這裡的lambda與map用得很 好.

*

Python2.4以後, sort和sorted的使用可以參考這片 Wiki: HowToSort

1.1.4. 迴圈

比如for迴圈. 當迴圈體很簡單時, 則迴圈的調用前頭(overhead) 會顯得很臃腫, 此時map又可以幫忙了. 比如你想把一個長數列 l=['a', 'b', ...]中的每個字串變成大寫, 可能會用:

切換行號顯示

1 import string 
2 newL = [] 
3 for s in l: newL.append( string.upper(s) )

用map就可以省去for迴圈的前頭:

切換行號顯示

1 import string 
2 newL = map (string.upper, l)

Guido的文章講得很詳細.

1.1.5. 局域變數 及 '.'

象上面, 若用 append = newL.append, 及換種import方法:

切換行號顯示

1 import string 
2 append = newL.append 
3 for s in l: append (string.upper(s))

會比在for中運行newL.append快一些, 為啥? 局域變數容易尋找.

俺自己就不比較時間了, Skip Montanaro的結果是:

基本迴圈: 3.47秒 
去點用局域變數: 1.79秒 
使用map: 0.54秒

1.1.6. try的使用

比如你想計算一個字串數列: l = ['I', 'You', 'Python', 'Perl', ...] 中每個詞出現的次數, 你可能會:

切換行號顯示

1 count = {} 
2 for s in l: 
3 if not count.has_key(s): count[s] = 0 
4 else: count[s] += 1

由於每次都得在count中尋找是否已有同名關鍵詞, 會很費時間. 而用try:

切換行號顯示

1 count ={} 
2 for s in l: 
3 try: count[s] += 1 
4 except KeyError: count[s] = 0

就好得多. 當然若經常出現例外時, 就不要用try了.

1.1.7. import語句

這好理解. 就是避免在函數定義中來import一個模組, 應全在 全域塊中來import

1.1.8. 大量資料處理

由於Python中的函數調用前頭(overhead)比較重, 所以處理大量 資料時, 應:

切換行號顯示

1 def f(): 
2 for d in hugeData: ... 
3 f()

而不要:

切換行號顯示

1 def f(d): ... 
2 for d in hugeData: f(d)

這點好象對其它語言也適用, 差不多是放之四海而皆準, 不過對 解釋性語言就更重要了.

1.1.9. 減少周期性檢查

這是Python的本徵功能: 周期性檢查有沒有其它緒(thread)或系 統訊號(signal)等要處理.

可以用sys模組中的setcheckinterval 來設定每次檢查的時間間隔.

預設是10, 即每10個虛擬指令 (virtual instruction)檢查一次.

當你不用緒並且也懶得搭理 系統訊號時, 將檢查周期設長會增加速度, 有時還會很顯著.

---編/譯完畢. 看來Python是易學難精了, 象圍棋?

2. 我們自個兒的體悟

請有心得者分享!

2.1. 故事

*

Python效能調優 ~ flydudu 分享

2.2. 思考

* 在“大量資料處理”小節裡,是不是說,不要再迴圈體內部調用函數,應該把函數放到外面?從Python2.2開始,"找出速度瓶頸",已經可以使用hotshot模組了.據說對程式運行效率的影響要比profile小. -- jacobfan 
* "由於Python中的函數調用前頭(overhead)比較重, 所以處理大量 資料時, 應: " 這句譯文中,overhead翻譯成"前頭"好象不妥.翻譯成"由於Python中函數調用的開銷比較大,..."要好些 -- jacobfan 
* 數組排序中講的方法真的會快點嗎? 真的快到我們值得放棄直接用sort得到得可讀性嗎?值得懷疑 -- hoxide 
* Python2.4以後 sort和sorted的使用更加靈活,link已經加到文中,我沒有比較過效率。-yichun 
* 關於 “try的使用”:

其實setdefault方法就是為這個目的設的:

切換行號顯示

1 count = {} 
2 for s in l: 
3 count.setdefault(s, 0) += 1

這個其實能做更多。通常遇到的問題是要把類似的東西group起來,所以你可能想用:

切換行號顯示

1 count = {} 
2 for s in l: 
3 count.setdefault(s, []).append(s)

但是這樣你只能把同樣的東西hash起來,而不是一類東西。比如說你有一個dict構成的list叫sequence,需要按這些dict的某個key value分類,你還要對分類後的每個類別裡面的這些dict各作一定的操作,你就需要用到Raymond實現的這個groupby,你就可以寫:

totals = dict((key, group) 
for key, group in groupby(sequence, lambda x: x.get('Age')))

- yichun

* shortStrs = [str(s) for s in shortStrs[i]]這句我在python2.5下報錯(i未定義),我改成shortStrs = [str(s) for s in shortStrs]就可以了。

 

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.