毫無疑問Python程序沒有編譯型語言高效快速. 甚至Python擁護者們會告訴你Python不適合這些領域. 然而,YouTube已用Python服務于每小時4千萬視頻的請求. 你所要做的就是編寫高效的代碼和需要時使用外部實現(C/C++)代碼. 這里有一些建議,可以幫助你成為一個更好的Python開發者:
- 使用內建函數: 你可以用Python寫出高效的代碼,但很難擊敗內建函數. 經查證. 他們非常快速.2.使用join()連接字符串. 你可以使用 "+" 來連接字符串. 但由于string在Python中是不可變的,每一個"+"操作都會創建一個新的字符串并復制舊內容. 常見用法是使用Python的數組模塊單個的修改字符;當完成的時候,使用 join() 函數創建最終字符串.
for chunk in input():
my_string.join(chunk)
- 使用Python多重賦值,交換變量
這在Python中即優雅又快速:
x, y = y, x
這樣很慢:
temp = x
x = y
y = temp
- 盡量使用局部變量
Python 檢索局部變量比檢索全局變量快. 這意味著,避免 "global" 關鍵字. - 盡量使用 "in"
使用 "in" 關鍵字. 簡潔而快速.
for key in sequence:
print “found”
- 使用延遲加載加速
將 "import" 聲明移入函數中,僅在需要的時候導入. 換句話說,如果某些模塊不需馬上使用,稍后導入他們. 例如,你不必在一開使就導入大量模塊而加速程序啟動. 該技術不能提高整體性能. 但它可以幫助你更均衡的分配模塊的加載時間. - 為無限循環使用 "while 1"
有時候在程序中你需一個無限循環.(例如一個監聽套接字的實例) 盡管 "while true" 能完成同樣的事, 但 "while 1" 是單步運算. 這招能提高你的Python性能.
while 1:
#do stuff, faster with while 1
while True:
# do stuff, slower with wile True
- 使用list comprehension
從Python 2.0 開始,你可以使用 list comprehension 取代大量的 "for" 和 "while" 塊. 使用List comprehension通常更快,Python解析器能在循環中發現它是一個可預測的模式而被優化.額外好處是,list comprehension更具可讀性(函數式編程),并在大多數情況下,它可以節省一個額外的計數變量。例如,讓我們計算1到10之間的偶數個數:
# the good way to iterate a range
evens = [ i for i in range(10) if i%2 == 0]
[0, 2, 4, 6, 8]
# the following is not so Pythonic
i = 0
evens = []
while i < 10:
if i %2 == 0: evens.append(i)
i += 1
[0, 2, 4, 6, 8]
- 使用xrange()處理長序列:
這樣可為你節省大量的系統內存,因為xrange()在序列中每次調用只產生一個整數元素。而相反 range(),它將直接給你一個完整的元素列表,用于循環時會有不必要的開銷。 - 使用 Python generator:
這也可以節省內存和提高性能。例如一個視頻流,你可以一個一個字節塊的發送,而不是整個流。例如, ```python
chunk = ( 1000 * i for i in xrange(1000))
chunk
<generator object at 0x7f65d90dcaa0>
chunk.next()
0
chunk.next()
1000
chunk.next()
2000 - 了解itertools模塊:
該模塊對迭代和組合是非常有效的。讓我們生成一個列表[1,2,3]的所有排列組合,僅需三行Python代碼:
import itertools
iter = itertools.permutations([1,2,3])
list(iter)
[(1, 2, 3), (1, 3, 2), (2, 1, 3), (2, 3, 1), (3, 1, 2), (3, 2, 1)]
- 學習bisect模塊保持列表排序:
這是一個免費的二分查找實現和快速插入有序序列的工具。也就是說,你可以使用:
import bisect
bisect.insort(list, element)
你已將一個元素插入列表中, 而你不需要再次調用 sort() 來保持容器的排序, 因為這在長序列中這會非常昂貴.
- 理解Python列表,實際上是一個數組:
Python中的列表實現并不是以人們通常談論的計算機科學中的普通單鏈表實現的。Python中的列表是一個數組。也就是說,你可以以常量時間O(1) 檢索列表的某個元素,而不需要從頭開始搜索。這有什么意義呢? Python開發人員使用列表對象insert()時, 需三思. 例如:>>> list.insert(0,item)
在列表的前面插入一個元素效率不高, 因為列表中的所有后續下標不得不改變. 然而,您可以使用list.append()在列表的尾端有效添加元素. 挑先deque,如果你想快速的在兩插入或時。它是快速的,因為在Python中的deque用雙鏈表實現。不再多說。 - 使用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
- 使用Schwartzian Transform 的 sort():
原生的list.sort()函數是非常快的。 Python會按自然順序排序列表。有時,你需要非自然順序的排序。例如,你要根據服務器位置排序的IP地址。 Python支持自定義的比較,你可以使用list.sort(CMP()),這會比list.sort()慢,因為增加了函數調用的開銷。如果性能有問 題,你可以申請Guttman-Rosler Transform,基于Schwartzian Transform. 它只對實際的要用的算法有興趣,它的簡要工作原理是,你可以變換列表,并調用Python內置list.sort() - > 更快,而無需使用list.sort(CMP() )->慢。 - Python裝飾器緩存結果:
“@”符號是Python的裝飾語法。它不只用于追查,鎖或日志。你可以裝飾一個Python函數,記住調用結果供后續使用。這種技術被稱為memoization的。下面是一個例子:
from functools import wraps
def memo(f):
cache = { }
@wraps(f)
def wrap(*arg):
if arg not in cache: cache['arg'] = f(*arg)
return cache['arg']
return wrap
我們也可以對 Fibonacci 函數使用裝飾器:
@memo
def fib(i):
if i < 2: return 1
return fib(i-1) + fib(i-2)
這里的關鍵思想是:增強函數(裝飾)函數,記住每個已經計算的Fibonacci值;如果它們在緩存中,就不需要再計算了.
- 理解Python的GIL(全局解釋器鎖):
GIL是必要的,因為CPython的內存管理是非線程安全的。你不能簡單地創建多個線程,并希望Python能在多核心的機器上運行得更快。這是因為 GIL將會防止多個原生線程同時執行Python字節碼。換句話說,GIL將序列化您的所有線程。然而,您可以使用線程管理多個派生進程加速程序,這些程 序獨立的運行于你的Python代碼外。 - 像熟悉文檔一樣的熟悉Python源代碼:
Python有些模塊為了性能使用C實現。當性能至關重要而官方文檔不足時,可以自由探索源代碼。你可以找到底層的數據結構和算法。 Python的源碼庫就是一個很棒的地方:http://svn.python.org/view/python/trunk/Modules