性能优化篇
1. 循环优化
a. 尽量减少循环内的计算,能循环外能实现的逻辑不放在循环内[2.22倍]
#坏的写法
data = [1,2,3,4,5,6,7]
for i in xrange(1000):
d_len = len(data) # 可在循环外实现
k = d_len + i
# 好的写法
data = [1,2,3,4,5,6,7]
d_len = len(data)
for i in xrange(1000):
k = d_len + i
b. 避免在循环中使用点操作
原因:每次调用obj.func时,python都会求该方法的值。所以可先用一个变量保存求得的值,避免循环每次求值
# 普通做法
lowerlist = ['this', 'is', 'lowercase']
upperlist = []
for word in lowerlist:
upperlist append(str.upper(word))
# 优化后做法
lowerlist = ['this', 'is', 'lowercase']
upperlist = []
upper = str.upper
append = upperlist.append
for word in lowerlist:
append(upper(word))
c. python2用xrange代替range
原因python2中xrange返回一个迭代器内存占用为常量,range返回一个数组内存占用大。注:python3中xrange不再存在,range返回一个迭代器。
2. 语言优化性能小技巧
a. 列表解析推导式优于for循环append构建 [3.3倍]
# 坏的写法
deamo_list = []
for i in xrange(10000):
deamo_list.append(i)
# 好的写法
deamo_list = [i for i in xrange(10000)]
c. 字典(dict)查找优于列表(list)
因为字典为hash表查找复杂度为O(1),list为数组复杂度为O(n)。当存在大量数据频繁查找时,将list转为dict是较好的选择。
# 一般做法
unsupport_items = ['a', 'b', 'is', 'python', 'jason', 'hello', 'hill', 'with', 'phone', 'test',
'dfdf', 'apple', 'pddf']
candicates = ['is', 'hat', 'new', 'list', 'old', '.']
target_items = []
for item in candicates:
if item not in unsupport_items:
target_items.append(item)
# 优化后写法
unsupport_items = ['a', 'b', 'is', 'python', 'jason', 'hello', 'hill', 'with', 'phone', 'test',
'dfdf', 'apple', 'pddf']
unsupport_items_dict = dict.fromkeys(unsupport_items, True) # list转为dict
candicates = ['is', 'hat', 'new', 'list', 'old', '.']
target_items = []
for item in candicates:
if item not in unsupport_items_dict:
target_items.append(item)
d. 集合(set)比列表(list)更适合做与集、交集、差集操作
set的union、intersection、difference操作比list的迭代要快。
e. 充分利用Lazy if-evaluation特性
大部分高级语言都支持条件表达式lazy evaluation特性。即if x and y表达式,如果x为false时y表达式值将不再计算。可将概率大、成本低、能快速确定条件表达式值的表达式放在前面,避免对低概率小或高成本表达式的计算。
# 一般做法
items = ['sss', 'bbb', 'ccc', 'tetasdfsdxx.txt', 'tet.txt', 'asdfa.pdf', 'xasdf.php']
txt_file = []
for item in iems:
if len(item) > 2 && item.endswith('.txt'):
txt_file.append(item)
# 好的写法
items = ['sss', 'bbb', 'ccc', 'tetasdfsdxx.txt', 'tet.txt', 'asdfa.pdf', 'xasdf.php']
txt_file = []
for item in iems:
if item.endswith('.txt') and len(item) > 2: # 通过判断.txt可快速过滤掉非文本文件,避免了对大量非txt文件名长度的无谓计算
txt_file.append(item)
f. if done is not None 比语句 if done != None更快
g. python的build in(内建)函数通常比较快
原因内建函数通常是经过语言特性优化的,性能较好。如:add(a, b)要优于 a + b
h. 使用关键字排序
使用关键字和默认的sort()方法排序,要优于自定义一个排序函数
# 例子:list
import operator
somelist = [(1, 5, 8), (6, 4, 5), (7, 3, 11)]
somelist.sort(key=operator.itemgetter(0)) # 按照第一个元素排序
somelist.sort(key=operator.itemgetter(1)) # 按照第二个元素排序
somelist.sort(key=operator.itemgetter(1)) # 按照第三个元素排序
# 例子:dict
import operator
somelist = [dict(a=1, b=2), dict(a=3,b=5),dict(a=44,b=33)]
somelist.sort(key=operator.attrgetter('a')) # 按照关键字'a'排序
somelist.sort(key=operator.attrgetter('b')) # 按照关键字'b'排序
i. 列表推导式
列表推导式优于for循环
# 普通写法:
alist = []
for i in xrange(10):
alist.append(i)
# 优化后写法1,[]生成一个列表:
alist = [i for i in xrange(10)]
# 优化后写法2, ()生成一个生成器:
alist_gen = (i for i in xrange(10))
# 优化后写法3,将生成器封装成一个方法
def seq_generator(amount):
return (i for x in xrange(amount))
for i in seq_generator(10):
print("index : %s" % i)
3. 字符串优化
a. 字符串操作join优于+或+=
因为python中字符串对象为不可变对象。对字符串的任何操作,如拼接、修改都会产生一个新的字符串对象,即产生持续的内存申请、copy操作,会对python性能有一定的影响。而join操作会先计算总内存量,一次性申请到位然后copy过去。join的内存申请次数少于+或+=,故性能更优。
# 不好的写法
items = ["I", "am", "from", "china"]
item_str = ""
for item in items:
item_str += item + " "
# 好的写法
items = ["I", "am", "from", "china"]
item_str = " ".join(items)
- b. 当对字符串可以使用正则表达或内置函数来处理时,优先选择内置函数
如:str.isalpha()、str.isdigit()、str.startswitch(('x', 'xy'))、str.endswith(('x', 'xy'))
# 一般做法
import re
is_digit_reg = re.compile("^[0-9]$")
data_str = "123"
if is_digit_reg(data_str):
print("%s is digit" % data_str)
# 优化后做法:
data_str = "123"
if data_str.isdigit():
print("%s is digit" % data_str)
- c. 对字符进行各耍比直接串联读取要快
原因:字符串的每次操作都会申请内存生成一个临时对象。
# 较好的写法
out_str = "%s from %s at time %s" % (name, city, date)
# 不好的写法
out_str = name + " from " + city + " at time " + date
- 合理使用生成器或yield
原因生成器对象所占内存空间大小和列表大小无关,故效率会较高些
4. 关键代码依赖于外部高性能包
即,利用C、C++等语言编写的喂不包,提高应用程序关键任务的性能。 但这些包通常不支持跨平台,移植性较差。如:Cython、PyInIne(python应用程序中直接使用C代码)、PyPy、Pyrex.
多使用cpython模块.