Python性能优化建议

时间:2022-12-09 19:29:45

1. 减少时间复杂度
在python中可以选取合适的数据结构来优化时间复杂度,比如list和set查找某一个元素的时间复杂度分别为O(n)和O(1)。
2. 合理安排and和or前后表达式的顺序
and:应该把满足条件的表达式放在前面,的放在后面
or:应该把满足条件的放在前面,的放在后面
3. 合理使用copy与deepcopy
cope为浅复制
deepcopy为深复制,采用递归复制的方式
效率方面,copy优于deepcopy
注意: 针对list和dict这类可变变量,直接赋值采用的是引用的方式,如果想要复制整个对象,则需要使用copy和deepcopy。
当要复制的对象为复合对象时,copy与deepcopy才有所不同。
复合对象的例子:[1,2,3,{1:2},[12,1]]
复制复合对象时,如果使用copy,则复制当前对象,并将内部对象的引用插入其中,如果使用deepcopy,则复制该对象,并复制内部对象插入其中。
所以,当复制的对象不是复合对象时,使用copy的效率要高,当复制的对象是符合对象时,并且需要当复合对象内部对象改变时并不影响原始的对象,则必须用deepcopy。
例如:

>>> a = [1,2,3,4]
>>> b = a
>>> a
[1, 2, 3, 4]
>>> b
[1, 2, 3, 4]
>>> a.append(5)
>>> a
[1, 2, 3, 4, 5]
>>> b
[1, 2, 3, 4, 5]
>>> from copy import copy,deepcopy
>>> b = copy(a) # 仅复制第一层元素的对象
>>> a
[1, 2, 3, 4, 5]
>>> b
[1, 2, 3, 4, 5]
>>> a.append(6)
>>> a
[1, 2, 3, 4, 5, 6]
>>> b
[1, 2, 3, 4, 5]
>>> c = [1,2,[1,2,3]]
>>> d = copy(c)
>>> e = deepcopy(c) # 复制所有对象
>>> d
[1, 2, [1, 2, 3]]
>>> e
[1, 2, [1, 2, 3]]
>>> c[2].append(4)
>>> c
[1, 2, [1, 2, 3, 4]]
>>> d
[1, 2, [1, 2, 3, 4]]
>>> e
[1, 2, [1, 2, 3]]

4.合理使用生成器(generator)和yield

>>> a = (i for x in range(1000))
>>> a
<generator object <genexpr> at 0x7fd526969be0>
>>> b = [i for i in range(1000)]

使用()可以生成generator对象,生成a所需时间比生成b所需时间要少,因为generator所占内存大小与列表的大小无关,因此效率要高一些。python2.x中可以生成generator对象的内置函数有xrange和itertools包。
但是, 使用如果需要循环遍历,则情况恰好相反,使用生成器的循环效率要低于普通的list或tuple。但是如果循环里有break,使用generator较好。可以用yield创建生成器,方法如下:

>>> def generate_list(n):
... for i in n:
... print i
... yield i+1
...
>>> generate_list([1,2,3,4])
<generator object generate_list at 0x7faf586816e0>
>>> for x in generate_list([1,2,3,4]):
... print "**",x
...
1
** 2
2
** 3
3
** 4
4
** 5
>>>

从上面可以看出,每循环一次,都会访问一次生成器,生成本次循环所需的元素。
5. 格式化字符串
有三种格式化字符串的方式:
(1)%
(2)format
(3)+
三种方式相比,+最快,format次之,%最差,但是速度相差不大。

>>> a, b = "hello", "world"
>>> "%s %s"%(a, b)
'hello world'
>>> "{0} {1}".format(a, b)
'hello world'
>>> a + " " + b
'hello world'
>>>

6.使用正确的序列化和反序列化方式
把对象转换为字节序列的过程称为对象的序列化。
把字节序列恢复为对象的过程称为对象的反序列化。
有三种反序列化的方式:eval()、json.loads()和cPickle.loads()
eval:不安全,对用户传递过来的参数使用eval进行反序列化,如果参数中是可执行命令,则对造成系统不安全。
速度方面,json>cPickle>eval
7. 使用dict和set 查找元素
python的dict和set都是用hash表来实现,查找元素的时间复杂度是O(1)。
8. 减少冗余数据
如用上三角或下三角的方式去保存一个大的对称矩阵。在0元素占大多数的矩阵里使用稀疏矩阵表示。
9. 调用用c实现的接口
10. 并行执行,多线程多进程
11. 优化循环
能在循环之外执行的语句不要放在循环之内
12. 使用join连接迭代器中的字符串
join()函数的参数可以试迭代对象,也可以是迭代器。该方式优于累加的方式。
累加的方式指:

>>> s = ["hello", "world", "!"]
>>> s1 = ""
>>> for s2 in s:
... s1 += s2
...
>>> s1
'helloworld!'
>>>

使用join:

>>> s = ["hello", "world", "!"]
>>> s1 = " ".join(s)
>>> s1
'hello world !'
>>> s = iter(s)
>>> s1 = " ".join(s)
>>> s1
'hello world !'
>>>

13.不利用中间变量交换两个元素的值
例如:

>>> a, b = 1, 2
>>> a, b = b, a
>>> a
2
>>> b
1
>>>

14.使用级联比较x<y<z而不是x<y and y<z
15.使用is来判断变量是否为True或False要比用==快
python2.x中True和False为全局变量,并不是关键字,True为1,False为0,值可以被更改,即可以写成True = 0, False = 1,在python3.x中才被设置为关键字。
16.python2.x中使用while 1要比while True快
17.使用**计算指数要比pow函数要快

>>> s = 2**3
>>> s
8
>>> s = pow(2,3)
>>> s
8