若干简单易实现的Python性能优化小tips。
部分参考:https://segmentfault.com/a/1190000000666603
一些tips在刷题过程确实得到验证,尚有一些未验证但在实际简单测试中效率有提升。
优化算法时间复杂度
不论什么语言,算法的时间复杂度对程序的执行效率都有决定性影响,在Python中可以通过选择合适的数据结构来优化时间复杂度,如list和set查找指定元素的时间复杂度分别为O(n)和O(1)。同时,可以根据具体情况,采用分治、贪心、动态规划等算法思想。(不过优化算法有些有时候也不是很容易实现,,,)
在算法的常见时间复杂度上排序如下:
使用dict或set查找元素
Python中的dict和set是使用hash表实现的,因此查找元素的最优时间复杂度为O(1),而list是线性表结构,其查询时间复杂度为O(n)。
因此,在需要频繁查找或访问的时候,依据实际情况使用dict或set,要比使用list更快。
1 | # run on jupyter-notebook |
使用set进行交并差运算
set的union、intersection、difference操作要比使用list迭代快,因此涉及list求交集、并集、差集的问题,可以通过转换为set来操作。
set的交并差操作语法:
- 交集:
set(list1)&set(list2)
- 并集:
set(list1)|set(list2)
- 差集:
set(list1)-set(list2)
使用list迭代方法求两个list交集:
1 | %%timeit -n 1000 |
将list转为set后求交集:
1 | %%timeit -n 1000 |
优化循环
对循环的优化遵循的原则是尽量减少循环过程中计算量,循环外可以做的事情不要放到循环内做,多重循环尽量将内层的计算提到上一层。
1 | # run on jupyter-notebook |
优化多个判断表达式的顺序
对于and,把满足条件少的表达式放在前面判断;对于or,把满足条件多的表达式放在后面判断。
Python中的条件表达式是lazy evaluation
的,也就是说对于表达式if a and b
,在a 为 false
的情况下,b
表达式的值将不再计算。
1 | # run on jupyter-notebook |
字符串的优化
Python中的字符串对象是不可改变的,因此对字符串的操作如拼接、修改等都会产生一个新的字符串对象,而不是基于原字符串,这种持续的copy过程会在一定程度上影响Python的性能,特别是处理文本较多的情况下。
字符串连接尽量使用join,而不是+
1 | %%timeit -n 100 |
1 | %%timeit -n 100 |
尽量使用内置函数判断,而不是正则表达式
在对字符串可以使用正则表达式或者内置函数进行判断时,尽量使用内置函数,如str.isalpha(), str.isdigit(), str.startswith(("x","y")), str.endswith(("x","y"))
。
不使用中间变量交换两个变量的值
使用a,b=b,a
的形式来交换a,b
两个变量的值。
(实际简单测试过程中,时间差距并不总是很大,还没深究速度差异的内在原因。)
借助中间变量:
1 | %%timeit -n 10000 |
不借助中间变量:
1 | %%timeit -n 10000 |
使用if is
,而不是==
使用if a is True
要比使用if a == True
快,同理if a is not Noe
要比if a != None
快。
1 | a = range(10000) |
使用级联比较x<y<z
1 | x, y, z = 1,2,3 |
使用while 1
,而不是while True
在Python2.x中,True是全局变量,而不是关键字?
1 | def while_1(): |
使用**
,而不是pow
1 | %timeit -n 10000 c = pow(2,20) |