閱讀Zen of Python,在Python解析器中輸入import this. 一個犀利的Python新手可能會注意到"解析"一詞, 認為Python不過是另一門腳本語言. "它肯定很慢!"
毫無疑問Python程式沒有編譯型語言高效快速. 甚至Python擁護者們會告訴你Python不適合這些領域. 然而,YouTube已用Python服務於每小時4千萬視頻的請求. 你所要做的就是編寫高效的程式碼和需要時使用外部實作(C/C++)程式碼. 這裡有一些建議,可以幫助你成為一個更好的Python開發者:
1. 使用內建函數: 你可以用Python寫出高效的程式碼,但很難擊敗內建函數. 經查證. 他們非常快速.2.使用join()連接字符串. 你可以使用"+" 來連接字符串. 但由於string在Python中是不可變的,每一個" +"操作都會建立一個新的字串並複製舊內容. 常見用法是使用Python的數組模組單一的修改字元;當完成的時候,使用join() 函數建立最終字串.
>>> #This is good to glue a large number of strings
>>> for chunk in input():
>>> my_string.join(chunk)
賦值使用這值優雅快速: >>> x, y = y, x 如此慢: >>> temp = x 4.盡量使用局部變數 Python 檢索局部變數比檢索全域變數快. 這表示,避免"global" 關鍵字.5. 盡量使用"in" 使用"in" 關鍵字. 簡潔而快速關鍵字. 簡潔>>> for key in sequence:
>>> print “found”
6. 使用延遲加載單詞
些模組不需馬上使用,稍後導入他們. 例如,你不必在一開使就導入大量模組而加速程序啟動. 該技術不能提高整體性能. 但它可以幫助你更均衡的分配模組的加載時間.
7. 為無限循環使用"while 1"
有時候在程序中你需一個無限循環.(例如一個監聽套接字的實例) 儘管"while true" 能完成同樣的事, 但"while 1 " 是單步驟運算. 招能提升你的Python效能.
>>> while 1:
>>> #do stuff, faster with while 1> # do stuff, slower with wile True
8. 使用list comprehension
從Python 2.0 開始,你可以使用list comprehension 取代大量的"for" 和"while" 塊. 使用解析 comprehension通常能在解析器循環中發現它是一個可預測的模式而被優化.額外好處是,list comprehension更具可讀性(函數式程式設計),並在大多數情況下,它可以節省一個額外的計數變數。例如,讓我們計算1到10之間的偶數個數:
>>> # the good way to iterate a range
>>> evens = [ i for i in range(10) if i%2 >>> evens = [ i for i in range(10) if i%2 ==== if i%2 == 0]
>>> [0, 2, 4, 6, 8]
>>> # the following is not so Pythonic
> >> i
> >> while i >>> if i %2 == 0: evens.append(i) >>> i += 1>>> i += 1
>>> i += 1]
9. 使用xrange()處理長序列:
這樣可為你節省大量的系統內存,因為xrange()在序列中每次調用只產生一個整數元素。而相反 range(),它將直接給你一個完整的元素列表,用於循環時會有不必要的開銷。
10. 使用 Python generator:
這也可以節省記憶體和提高效能。例如一個視訊串流,你可以一個一個位元組塊的發送,而不是整個串流。例如,
>>> chunk = ( 1000 * i for i in xrange(1000))
>>> chunk
>; 0 >>> chunk. next() 1000 >>> chunk.next() 200011. 了解非常有效且非常有效的組合 讓我們產生一個清單[1,2,3]的所有排列組合,只需三行Python程式碼:
>>> import itertools
>>> iter = itertools.permutations([1,2,333] >>> list(iter) [(1, 2, 3), (1, 3, 2), (2, 1, 3), (2, 3, 1), (3, 1, 2) , (3, 2, 1)] 12. 學習bisect模組保持列表排序: 這是一個免費的二分查找實現和快速插入有序序列的工具。也就是說,你可以使用: >>> import bisect >>> bisect.insort(list, element) 容器的排序, 因為這在長序列中這會非常昂貴. 13. 理解Python列表,實際上是一個數組: Python中的列表實現並不是以人們通常談論的計算機科學中的普通單鍊錶實現的。 Python中的列表是一個陣列。也就是說,你可以以常數時間O(1) 檢索列表的某個元素,而不需要從頭開始搜尋。這有什麼意義呢? Python開發人員使用列表對象insert()時, 需三思. 例如:>>> list.insert(0,item) 在列表的前面插入一個元素效率不高, 因為列表中的所有後續下標不得不改變. 然而,您可以使用list.append()在列表的尾端有效添加元素. 挑先deque,如果你想快速的在兩插入或時。它是快速的,因為在Python中的deque用雙鍊錶實現。不再多說。 14. 使用dict 和 set 測試成員: 檢查一個元素是在dicitonary或set是否存在 這在Python中非常快的。這是因為dict和set使用哈希表來實現。查找效率可以達到O(1)。因此,如果您需要經常檢查成員,使用set 或dict做為你的容器. >>> mylist = ['a', 'b', 'c'] #Slower, check membership with list: > >> 'c' in mylist >>> True >>> myset = set(['a', 'b', 'c']) # Faster, check membership with set: > c' in myset: >>> True 15. 使用Schwartzian Transform 的sort(): 原生的list.sort()函數是非常快速的。 Python會依照自然順序排序列表。有時,你需要非自然順序的排序。例如,你要依照伺服器位置排序的IP位址。 Python支援自訂的比較,你可以使用list.sort(CMP()),這會比list.sort()慢,因為增加了函數呼叫的開銷。如果效能有問題,你可以申請Guttman-Rosler Transform,基於Schwartzian Transform. 它只對實際的要用的演算法有興趣,它的簡要工作原理是,你可以變換列表,並調用Python內建list.sort() - > 更快,而無需使用list.sort(CMP() )->慢。 16. Python裝飾器快取結果: 「@」符號是Python的裝飾語法。它不只用於追查,鎖或日誌。你可以裝飾一個Python函數,記得呼叫結果供後續使用。這種技術被稱為memoization的。以下是一個範例: >>> from functools import wraps >>> def memo(f): >> (f) >>> def wrap(*arg): >>> if arg not in cache: cache['arg'] = f(*arg) return wrap 我們也可以對Fibonacci 函數使用裝飾器: >>> @memo >>> def fib(i): return fib(i- 1) + fib(i-2) 這裡的關鍵思想是:增強函數(裝飾)函數,記住每個已經計算的Fibonacci值;如果它們在緩存中,就不需要再計算了. 17. 理解Python的GIL(全域解釋器鎖定): GIL是必要的,因為CPython的記憶體管理是非執行緒安全的。你不能簡單地創建多個線程,並希望Python能在多核心的機器上運行得更快。這是因為 GIL將會防止多個原生執行緒同時執行Python字節碼。換句話說,GIL將序列化您的所有線程。然而,您可以使用執行緒管理多個派生進程加速程序,這些程 序獨立的運行於你的Python程式碼外。 18. 像熟悉文件一樣的熟悉Python原始碼: Python有些模組為了效能使用C實作。當效能至關重要而官方文件不足時,可以自由探索原始程式碼。你可以找到底層的資料結構和演算法。 Python的原始碼庫就是一個很棒的地方:http://svn.python.org/view/python/trunk/Modules 結論: 這些不能替代大腦思考. 打開引擎蓋充分了解是開發者的職責,使得他們不會快速拼湊出一個垃圾設計. 本文的Python建議可以幫助你獲得好的性能. 如果速度還不夠快, Python將需要借助外力:分析和運行外部程式碼.我們將在本文的第二部分中涉及.