这个系列主要是总结一些《改善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