1. 在列表中查找:python
對於已經排序的列表考慮用bisect模塊來實現查找元素,該模塊將使用二分查找實現git
def find(seq, el) : pos = bisect(seq, el) if pos == 0 or ( pos == len(seq) and seq[-1] != el ) : return -1 return pos - 1
而快速插入一個元素能夠用:正則表達式
bisect.insort(list, element)
這樣就插入元素而且不須要再次調用 sort() 來保序,要知道對於長list代價很高.算法
2. set代替列表: 編程
好比要對一個list進行去重,最容易想到的實現:數組
seq = ['a', 'a', 'b'] res = [] for i in seq: if i not in res: res.append(i)
顯然上面的實現的複雜度是O(n2),若改爲:數據結構
seq = ['a', 'a', 'b'] res = set(seq)
複雜度立刻降爲O(n),固然這裏假定set能夠知足後續使用。架構
另外,set的union,intersection,difference等操做要比列表的迭代快的多,所以若是涉及到求列表交集,並集或者差集等問題能夠轉換爲set來進行,平時使用的時候多注意下,特別當列表比較大的時候,性能的影響就更大。app
3. 使用python的collections模塊替代內建容器類型:框架
collections有三種類型:
列表是基於數組實現的,而deque是基於雙鏈表的,因此後者在中間or前面插入元素,或者刪除元素都會快不少。
defaultdict爲新的鍵值添加了一個默認的工廠,能夠避免編寫一個額外的測試來初始化映射條目,比dict.setdefault更高效,引用python文檔的一個例子:
#使用profile stats工具進行性能分析
>>> from pbp.scripts.profiler import profile, stats >>> s = [('yellow', 1), ('blue', 2), ('yellow', 3), ... ('blue', 4), ('red', 1)] >>> @profile('defaultdict') ... def faster(): ... d = defaultdict(list) ... for k, v in s: ... d[k].append(v) ... >>> @profile('dict') ... def slower(): ... d = {} ... for k, v in s: ... d.setdefault(k, []).append(v) ... >>> slower(); faster() Optimization: Solutions [ 306 ] >>> stats['dict'] {'stones': 16.587882671716077, 'memory': 396, 'time': 0.35166311264038086} >>> stats['defaultdict'] {'stones': 6.5733464259021686, 'memory': 552, 'time': 0.13935494422912598}
可見性能提高了快3倍。defaultdict用一個list工廠做爲參數,一樣可用於內建類型,好比long等。
除了實現的算法、架構以外,python提倡簡單、優雅。因此正確的語法實踐又頗有必要,這樣纔會寫出優雅易於閱讀的代碼。
(1)用join代替 '+' 操做符,後者有copy開銷;
(2)同時當對字符串可使用正則表達式或者內置函數來處理的時候,選擇內置函數。如str.isalpha(),str.isdigit(),str.startswith((‘x’, ‘yz’)),str.endswith((‘x’, ‘yz’))
(3)字符格式化操做優於直接串聯讀取:
str = "%s%s%s%s" % (a, b, c, d) # efficient str = "" + a + b + c + d + "" # slow
2. 善用list comprehension(列表解析) & generator(生成器) & decorators(裝飾器),熟悉itertools等模塊:
(1) 列表解析,我以爲是python2中最讓我印象深入的特性,舉例1:
>>> # the following is not so Pythonic >>> numbers = range(10) >>> i = 0 >>> evens = [] >>> while i < len(numbers): >>> if i %2 == 0: evens.append(i) >>> i += 1 >>> [0, 2, 4, 6, 8] >>> # the good way to iterate a range, elegant and efficient >>> evens = [ i for i in range(10) if i%2 == 0] >>> [0, 2, 4, 6, 8]
舉例2:
def _treament(pos, element): return '%d: %s' % (pos, element)
f = open('test.txt', 'r') if __name__ == '__main__': #list comps 1 print sum(len(word) for line in f for word in line.split()) #list comps 2 print [(x + 1, y + 1) for x in range(3) for y in range(4)] #func print filter(lambda x: x % 2 == 0, range(10)) #list comps3 print [i for i in range(10) if i % 2 == 0] #list comps4 pythonic print [_treament(i, el) for i, el in enumerate(range(10))] output: 24 [(1, 1), (1, 2), (1, 3), (1, 4), (2, 1), (2, 2), (2, 3), (2, 4), (3, 1), (3, 2), (3, 3), (3, 4)] [0, 2, 4, 6, 8] [0, 2, 4, 6, 8] ['0: 0', '1: 1', '2: 2', '3: 3', '4: 4', '5: 5', '6: 6', '7: 7', '8: 8', '9: 9']
沒錯,就是這麼優雅簡單。
(2) 生成器表達式在python2.2引入,它使用'lazy evaluation'思想,所以在使用內存上更有效。引用python核心編程中計算文件中最長的行的例子:
f = open('/etc/motd, 'r') longest = max(len(x.strip()) for x in f) f.close() return longest
這種實現簡潔並且不須要把文件文件全部行讀入內存。
(3) python在2.4引入裝飾器,又是一個讓人興奮的特性,簡單來講它使得函數和方法封裝(接收一個函數並返回加強版本的函數)更容易閱讀、理解。'@'符號是裝飾器語法,你能夠裝飾一個函數,記住調用結果供後續使用,這種技術被稱爲memoization的,下面是用裝飾器完成一個cache功能:
import time import hashlib import pickle from itertools import chain cache = {} def is_obsolete(entry, duration): return time.time() - entry['time'] > duration def compute_key(function, args, kw): #序列化/反序列化一個對象,這裏是用pickle模塊對函數和參數對象進行序列化爲一個hash值 key = pickle.dumps((function.func_name, args, kw)) #hashlib是一個提供MD5和sh1的一個庫,該結果保存在一個全局字典中 return hashlib.sha1(key).hexdigest() def memoize(duration=10): def _memoize(function): def __memoize(*args, **kw): key = compute_key(function, args, kw) # do we have it already if (key in cache and not is_obsolete(cache[key], duration)): print 'we got a winner' return cache[key]['value'] # computing result = function(*args, **kw) # storing the result cache[key] = {'value': result,- 'time': time.time()} return result return __memoize return _memoize @memoize() def very_very_complex_stuff(a, b, c): return a + b + c print very_very_complex_stuff(2, 2, 2) print very_very_complex_stuff(2, 2, 2) @memoize(1) def very_very_complex_stuff(a, b): return a + b print very_very_complex_stuff(2, 2) time.sleep(2) print very_very_complex_stuff(2, 2)
運行結果:
6
we got a winner
6
4
4
裝飾器在不少場景用到,好比參數檢查、鎖同步、單元測試框架等,有興趣的人能夠本身進一步學習。
3. 善用python強大的自省能力(屬性和描述符):自從使用了python,真的是驚訝原來自省能夠作的這麼強大簡單,關於這個話題,限於內容比較多,這裏就不贅述,後續有時間單獨作一個總結,學習python必須對其自省好好理解。
使用多重賦值來swap元素:
x, y = y, x # elegant and efficient
而不是:
temp = x x = y y = temp
9. 三元操做符(python2.5後):V1 if X else V2,避免使用(X and V1) or V2,由於後者當V1=""時,就會有問題。
10. python之switch case實現:由於switch case語法徹底可用if else代替,因此python就沒 有switch case語法,可是咱們能夠用dictionary或lamda實現:
switch case結構:
switch (var) { case v1: func1(); case v2: func2(); ... case vN: funcN(); default: default_func(); }
dictionary實現:
values = { v1: func1, v2: func2, ... vN: funcN, } values.get(var, default_func)()
lambda實現:
{ '1': lambda: func1, '2': lambda: func2, '3': lambda: func3 }[value]()
用try…catch來實現帶Default的狀況,我的推薦使用dict的實現方法。