有关python的几点性能建议。
从python.org翻译过来的。
-----------------------------------------------
写在翻译之初:;
使用这些方法的时候一定要测试,不要盲从的相信一种方法一定好于或者坏于另外一种。
-----------------------------------------------
写代码实现一个功能要有以下这几部分:
1、Get it right
2、Test it's right
3、Profile if slow
4、Optimise
5、Repeat from 2
------------------------第一、字符串连接------------------------
在python中,字符串是不可变的。一个字符串创造出来之后,如果想给字符串增加或者减少一点内容,那么就会构造一个新的字符串并返回给你。关于不可变性,这里不赘述。
看下面这个写法:
s = ""
for substring in list:
s += substring
如果是构造大字符串,那么这个效率是非常低的。
如果我们想通过一个函数生成一些字符串并追加到一个原始字符串中,最初的写法可能是这样:
s = ""
for x in list:
s += some_function(x)
但是为了高效率,要这样写:
s=''
L=[some_function(i) for i in list]
s=''.join(L)
尽量避免下面这种写法:
out = "<html>" + head + prologue + query + tail + "</html>"
而是用下面的方法来做:
out = "<html>%s%s%s%s</html>" % (head, prologue, query, tail)
或者用下面的方法会更好:
# -*- coding: cp936 -*-
a="a"
b='b'
c='c'
d='d'
out = "<html>%(a)s%(b)s%(c)s%(d)s</html>" % locals()
print out
上面的语句,涉及到了两个知识点。一个是locals()函数,它将返回所有局部数据。
另外就是字符串连接问题。使用参数的%(variable)s能够得到一个字符串。
有时候在程序中你需一个无限循环。(例如一个监听套接字的实例) 尽管 "while True" 能完成同样的事,但 "while 1" 是单步运算。这招能提高你的Python性能。
>>> while 1:
>>> #do stuff, faster with while 1
>>> while True:
>>> # do stuff, slower with wile True
-------------------------循环----------------------------------
for循环是最常用的循环了。但是如果for的循环体足够短小的话,那么for循环本身的开销就会相对来说较大了。那么可以使用map来代替。如下:
>>> oldlist=['a','b','c']
>>> newlist = map(str.upper, oldlist)
>>> newlist
['A', 'B', 'C']
>>> oldlist
['a', 'b', 'c']
>>> newlist=[]
>>> for x in oldlist:
newlist.append(x.upper())
>>> newlist
['A', 'B', 'C']
>>> newlist=[]
>>> newlist=map(str.upper,oldlist)
>>> newlist
['A', 'B', 'C']
上面for循环只是把oldlist的内容都改成了大写。改用map!
或者上面的for循环实现的功能,可以简写为:
newlist=[x.upper() for x in oldlist]
也可以使用生成器的方式。生成器的好处是,不需要一次生成全部的列表。而是需要的时候才调用next函数生成下一个元素。
>>> a= (s.upper() for s in oldlist)
>>> type(a)
<type 'generator'>
>>> a.next()
'A'
>>> a.next()
'B'
>>> a.next()
'C'
从上面的代码可以看到,a的类型是一个generator。
Guido van Rossum wrote a much more detailed (and succinct) examination of loop optimization that is definitely worth reading.
---------------------优化函数查找------------------
在一个for循环中,假设还是我们上面将小写改成大写的for循环,那个upper函数每次都要去查找。所以可以做如下优化:
>>> myupper=str.upper
>>> list=['a','b','c']
>>> newlist=[]
>>> for x in list:
newlist.append(myupper(x))
>>> newlist
['A', 'B', 'C']
>>>
这样, upper函数就不需要每次都进行查找了(只需要设置myupper的时候查找一次即可)。
另外,上面的append函数也可以做这样的优化:
>>> myupper=str.upper
>>> list=['a','b','c']
>>> newlist=[]
>>> myappend=list.append
>>> myappend=newlist.append
>>> for x in list:
myappend(myupper(x))
>>> newlist
['A', 'B', 'C']
>>>
--------------------优化判断次数-----------------------
看下面代码:
wdict = {}
for word in words:
if word not in wdict:
wdict[word] = 0
wdict[word] += 1
上面的代码中,每次处理一个单词的时候,都要经过一次if判断。如果有些词在words中出现很多次,那么这些多次的if判断就是浪费的,很没有效率。可以使用try语句来实现减少判断这个功能(这是一个trick,不提倡)。
wdict = {}
for word in words:
try:
wdict[word] += 1
except KeyError:
wdict[word] = 1
在try语句失败之后,会进入except,将word设置为1。这里必须捕捉的是KeyError。如果这里什么都不写,说明可以捕捉任何异常。那是不合适的。
在python2.x中,可以使用字典的get函数。因为get函数可以返回一个默认值。
wdict = {}
get=wdict.get
for word in words:
wdict[word]=get(word,0)+1
------------------------------------------------------------
--------------------写在最后---------------------
python中,如何反转一个字符串?
>>> a='123456789'
>>> b=a[::-1]
>>>
>>> b
'987654321'
这个反转方法是使用了分片中,步长是负数的机制。步长如果是负数,那么python会从字符串最后开始往前进行分片。