這個系列主要是總結一些《改善python程序的91個建議》的學習筆記,但願能夠對本身和讀者有所幫助。本文是該系列第二部分,第一部分請見 Part1html
23 避免finally中可能發生的陷阱python
24 深刻理解None,正確判斷對象是否爲空函數
25 鏈接字符串應優先使用join而不是+ —-> 字符串規模比較大的時候性能
‘xxxx{0}xxxx{1}’.format(n1,n2)
s = ( 'aaaaa' 'bbbb' 'ccccc' )
· 3對雙引號會把換行符和前導空格當作字符串的一部分學習
· str.startswith和endswith中匹配參數可使用元組,有一個匹配上就返回T大數據
from collections import Counter some_data = ['a','2',2,4,5,'2','b',4,7,'a',5,'d','a','z'] print Counter(some_data) >>>Counter({'a': 3, '2': 2, 4: 2, 5: 2, 2: 1, 'b': 1, 7: 1, 'd': 1, 'z': 1})
· Counter類屬於字典類的子類,是一個容器對象,主要用來統計散列對象。優化
# 取值 xx = Counter(some_data) print xx.['a']
36 單例模式ui
class Test(object): is_instance = None is_first = True def __new__(cls, *args, **kwargs): if cls.is_instance == None: cls.is_instance = object.__new__(cls) return cls.is_instance def __init__(self, name): if Test.is_first: self.name = name Test.is_first = False test1 = Test('lf1') print(id(test1)) # 2136967041656 print(test1.name) # lf1 test2 = Test('lf2') print(id(test2)) # 2136967041656 print(test2.name) # lf1
37 利用cProfile 定位性能瓶頸spa
## test_cprofile.py import time def foo(): sum = 0 for i in range(100): sum += i time.sleep(.5) return sum if __name__ == "__main__": foo()
if __name__ =="__main__": import cProfile cProfile.run("foo()")
輸出以下:.net
第二種方式:python -m cProfile test_cprofile.py
· cProfile 的統計結果以及各項意義
統計項 | 意義 |
---|---|
ncalls | 函數的調用次數 |
tottime | 函數總計運行時間,不含調用的函數運行時間 |
percall | 函數運行一次的平均時間,等於tottime/ncalls |
cumtime | 函數總計運行時間,含調用的函數運行時間 |
percall | 函數運行一次的平均時間,等於cumtime/ncalls |
filename:lineno(function) | 函數所在的文件名,函數的行號,函數名 |
# ....略 if __name__ == "__main__": import cProfile cProfile.run("foo()", "prof.txt") import pstats p = pstats.Stats("prof.txt") # sort_stats(key,[...]) 以key排序 print_stats()輸出結果 p.sort_stats("time").print_stats()
參數 | 參數的意義 |
---|---|
ncalls | 被調用次數 |
cumulative | 函數運行的總時間 |
file | 文件名 |
module | 模塊名 |
pcalls | 簡單調用統計(兼容舊版,未統計遞歸調用) |
line | 行號 |
name | 函數名 |
nfl | Name,file,line |
stdname | 標準函數名 |
time | 函數內部運行時間(不計調用子函數的時間) |
38 掌握循環優化的基本技巧
· 減小循環內部的計算
# 1 for i in range(iter): d = math.sqrt(y) j += i*d # 2 比第一種快 40%~60% d = math.sqrt(y) for i in range(iter): j += i*d
· 將顯式循環改成隱式循環
"""求等差數列1,2,3,...n的和""" # 1 sum = 0 n = 10 for i in range(n+1): sum = sum + i print(sum) # 2 直接用數學知識 n*(n+1)/2 負面影響就是犧牲了代碼的可讀性 需添加清晰和恰當的註釋是很是必要的 n = 10 print(n*(n+1)/2)
· 在循環中儘可能引用局部變量.在python命名空間中局部變量優先搜索,所以局部變量的查詢會比全局變量要快
# 1 x = [10,34,56,78] def f(x): for i in range(len(x)): x[i] = math.sin(x[i]) return x # 2 性能提升10%~15% def g(x): loc_sin = math.sin for i in range(len(x)): x[i] = loc_sin(x[i]) return x
· 關注內層嵌套循環,儘可能將內層循環的計算往上層移,減小內層的計算
# 1 for i in range(len(v1)): for j in range(len(v2)): x = v1p[i]+ v2[j] # 2 for i in range(len(v1)): vli = v1[i] for j in range(len(v2)): x = vli + v2[j]
參考:
《改善python程序的91個建議》
https://blog.csdn.net/qq_31603575/article/details/80177153
https://www.cnblogs.com/cotyb/p/5452602.html
https://www.cnblogs.com/cotyb/tag/pythonic/
https://medium.freecodecamp.org/an-a-z-of-useful-python-tricks-b467524ee747