返回顶部
关闭软件导航
位置:首页 > 技术分享 > SEO优化>Python性能优化的20条建议

算法的时间复杂度对程序的执行效率影响很大,在Python中可以通过选择合适的数据结构来优化时间复杂度,如list和set查找某一个元素的时间复杂度分别是O(n)和O(1)。不同的场景有不同的优化方式,总得来说,一般有分治,分支界限,贪心,动态规划等思想。

减少冗余数据

Python性能优化的20条建议

如用上三角或下三角的方式去保存一个大的对称矩阵。在0元素占大多数的矩阵里使用稀疏矩阵表示。

合理使用copy与deepcopy

对于dict和list等数据结构的对象,直接赋值使用的是引用的方式。而有些情况下需要复制整个对象,这时可以使用copy包里的copy和deepcopy,这两个函数的不同之处在于后者是递归复制的。效率也不一样:(以下程序在ipython中运行)

importcopya=range(100000)%timeit-n10copy.copy(a)#运行10次copy.copy(a)%timeit-n10copy.deepcopy(a)10loops,bestof3:1.55msperloop10loops,bestof3:151msperloop

timeit后面的-n表示运行的次数,后两行对应的是两个timeit的输出,下同。由此可见后者慢一个数量级。

使用dict或set查找元素

pythondict和set都是使用hash表来实现(类似c++11标准库中unordered_map),查找元素的时间复杂度是O(1)

a=range(1000)s=set(a)d=dict((i,1)foriina)%timeit-n10000100ind%timeit-n10000100ins10000loops,bestof3:43.5nsperloop10000loops,bestof3:49.6nsperloop

dict的效率略高(占用的空间也多一些)。

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

%timeit-n100a=(iforiinrange(100000))%timeit-n100b=[iforiinrange(100000)]100loops,bestof3:1.54msperloop100loops,bestof3:4.56msperloop

使用()得到的是一个generator对象,所需要的内存空间与列表的大小无关,所以效率会高一些。在具体应用上,比如set(iforiinrange(100000))会比set([iforiinrange(100000)])快。

但是对于需要循环遍历的情况:

%timeit-n10forxin(iforiinrange(100000)):pass%timeit-n10forxin[iforiinrange(100000)]:pass10loops,bestof3:6.51msperloop10loops,bestof3:5.54msperloop

后者的效率反而更高,但是假如循环里有break,用generator的好处是显而易见的。yield也是用于创建generator:

defyield_func(ls):foriinls:yieldi+1defnot_yield_func(ls):return[i+1foriinls]ls=range(1000000)%timeit-n10foriinyield_func(ls):pass%timeit-n10foriinnot_yield_func(ls):pass10loops,bestof3:63.8msperloop10loops,bestof3:62.9msperloop

对于内存不是非常大的list,可以直接返回一个list,但是可读性yield更佳(人个喜好)。

python2.x内置generator功能的有xrange函数、itertools包等。

优化循环

循环之外能做的事不要放在循环内,比如下面的优化可以快一倍:

a=range(10000)size_a=len(a)%timeit-n1000foriina:k=len(a)%timeit-n1000foriina:k=size_a1000loops,bestof3:569sperloop1000loops,bestof3:256sperloop

优化包含多个判定表达式的顺序

对于and,应该把满足条件少的放在前面,对于or,把满足条件多的放在前面。如:

a=range(2000)%timeit-n100[iforiinaif10i20or1000i2000]%timeit-n100[iforiinaif1000i2000or100i20]%timeit-n100[iforiinaifi%2==0andi1900]%timeit-n100[iforiinaifi1900andi%2==0]100loops,bestof3:287sperloop100loops,bestof3:214sperloop100loops,bestof3:128sperloop100loops,bestof3:56.1sperloop

使用join合并迭代器中的字符串

In[1]:%%timeit...:s=''...:foriina:...:s+=i...:10000loops,bestof3:59.8sperloopIn[2]:%%timeits=''.join(a)...:100000loops,bestof3:11.8sperloop

join对于累加的方式,有大约5倍的提升。

选择合适的格式化字符方式

s1,s2='ax','bx'%timeit-n100000'abc%s%s'%(s1,s2)%timeit-n100000'abc{0}{1}'.format(s1,s2)%timeit-n100000'abc'+s1+s2100000loops,bestof3:183nsperloop100000loops,bestof3:169nsperloop100000loops,bestof3:103nsperloop

三种情况中,%的方式是很慢的,但是三者的差距并不大(都非常快)。(个人觉得%的可读性很好)

不借助中间变量交换两个变量的值

In[3]:%%timeit-n10000a,b=1,2....:c=a;a=b;b=c;....:10000loops,bestof3:172nsperloopIn[4]:%%timeit-n10000a,b=1,2a,b=b,a....:10000loops,bestof3:86nsperloop

使用a,b=b,a而不是c=a;a=b;b=c;来交换a,b的值,可以快1倍以上。

使用ifis

a=range(10000)%timeit-n100[iforiinaifi==True]%timeit-n100[iforiinaifiisTrue]100loops,bestof3:531sperloop100loops,bestof3:362sperloop

使用ifisTrue比if==True将近快一倍。

使用级联比较xyz

x,y,z=1,2,3%timeit-n1000000ifxyz:pass%timeit-n1000000ifxyandyz:pass1000000loops,bestof3:101nsperloop1000000loops,bestof3:121nsperloop

xyz效率略高,而且可读性更好。

while1比whileTrue更快

defwhile_1():n=100000while1:n-=1ifn=0:breakdefwhile_true():n=100000whileTrue:n-=1ifn=0:breakm,n=1000000,1000000%timeit-n100while_1()%timeit-n100while_true()100loops,bestof3:3.69msperloop100loops,bestof3:5.61msperloop

艇狼痛乙嚼蓄酸舍崭组丑蜓伴北滤烘某斗郎锐水斧理卵河破垫铺学打辅烟捧身刮交弯虫兽住算父铃情亿贸辜亭瞎圾享胀潜帐辫阔泥万件摸床咱弄仍光冬南勿喊饲倍盯馅士默后都丹岛潮扫床洁滨沉恳冶导恨焰逼浇冶个掌闻童灭赚抹控规匪策启杆骄听肯还右志克左赶举伤叙菌朽催寿捏侧便将未炒仓肉狱通订谣味放巧久赛齐隐园羊哪赔拥废次宋鱼阁尽雪松偿林辉水表滋艳武趴升树充炕第豆微鸦别经饥策睡宽翁罢两店ek0bJF。Python性能优化的20条建议。服务器宕机对seo的影响,淘宝SEO卖虚拟商品 月入几十万,成都百度推广我选乐云seo十年,西安英文seo招聘

如果您觉得 Python性能优化的20条建议 这篇文章对您有用,请分享给您的好友,谢谢!