Python的代码优化

因为现阶段写的Python代码主要是用于测试,暂时没有对性能方面没有太注意, 这篇转载的文章,虽然没有完全理解,但是其中提到的很多问题还是在以后写代码过程中值得注意的。

本文摘录自《深入学习:Python程序开发》由ChumpKlutz原创。


为了防止程序执行缓慢,读者可能会考虑遵从一些基本的Python优化规则.从开始设计程序时就以此为指导,必将会得到令人满意的总体性能.

本节的目的就是为生成高性能的Python程序提供指导.注意,作者没有介绍所有内容,而是讲述了一些基本的概念.

 有很多方法可以用来缩短程序的执和时间.记住,每当执行一个Python脚本之时,就会调用一个解释器.因而为了对此做补偿,需要对代码做点工作.这与Python是一种解释性语言有很大关系,不过通过减少需加以分析的语句的数量,也会减少解释器的总开销.

顺便提及,Python解释器具有一个命令么选项(-0代表optimize--优化),使得程序以不执行某些字节操作的方式加以执行.一般来说,该选项用于去除节字码中给出异常产生的行号的注释,并不编译doc字符串和一些其他东西.该标志不会给出太多的速度增益,而且它会使用程序难以调试.

以下是一些有用的优化提示:

变量--取决于如何定义定义一,解释器花费或多或少的时间尝试计算出它们的值.Python在尝试判定变量名时利用动态作用域规则进行处理.当它在代码中找到一个变量时,首先通过查看局部名空间字典考察该变量是不是一个局部变量.如果找到该变量,就抓取该变量的值.否则再在全局名字空间字典中进行搜索,如果需要,还会搜索内置名字空间.因此,局部变量比其他类型变量的搜索速度要快得多,因而获得它们的值也要快得多.局部变量搜索速度快是因为它们对应于数组中的下标操作,而全局变量搜索则对应于散列表搜索.一个良好的优化方法是:如果在函数中使用了很多全局变量,把它们的值赋给局部变量可能会有很大帮助.

模块--在一个脚本之中,只需一次导入一个外部模块即可.因此,在代码中不需要多个import语句.实际上,应该避免在程序中尝试再导入模块.根据以往的经验,应该把所有的import语句放在程序头的最开始部分.然而,对一个模块多次调用import不会真正造成问题,因为它只是一个字典查找.如果必须要对一个外部模块的某些特定属性进行大量引用,开始编写代码之前,应该考虑将这些元素复制到单个变量中(当然,如果可能的话)--特另是如果引用在一个循环内部进行.只要导入模块,解释器就查找该模块的字节编译版.如果未找到,它会自动对模块进行字节编译并生成.pyc文件.因此,当下次尝试导入此模块时,字节编译文件就在那里.正如读者所体会的那样.pyc文件比常规.py文件执行起来快很多,因为它们在执行之前就已经经解释器解释过.这里的建议是尽量使用字节编译模块.不论是否拥有.pyc文件Python代码都以相同的速度执行.惟一的区别是如果存在.pyc文件,启动将会有所加快.代码的实际运行速度没有区别.

字符串--需要把字符串与其他变量连接时就使用格式化字符串.请查看下面的连接形式.

    name = " Andre "
    
print   " Hello  "   +  name
    
print   " Hello %s "   %  name

显然与第一个语句相比,第二个print语句更加优化.第三行中的括号是不需要的.另一种选择可以是:

     print   " Hello " , name

Tkinter--避免创建不需要的配件实例.如果在创建完配件之后不打算处理其属性,则应坚持对该类进行直接调用.在一个GUI应用程序中,这不会对运行速度造成多大影响--仅仅会在启动期间有所影响.

 没有理由这样声明:

    mybutton = Button(root,text = " Close " )
    mybutton.pack(side
= right)

此时可以简单地使用:

    mybutton = Button(root,text = " Close " ).pack(side = right)

 这样,解释器可处理的变量就少了一个.

 在此插一句,如果使用IDLE调试Tkinter程序,则需要注释掉mainloop()命令.这是因为IDLE已经运行在Tkinter的主循环之中,调用另一个可能会冻结整个开发环境。

循环--可以在循环中优化大量事件以便它们可平稳运行.下面就是可优化操作的简短清单.在内循环中应该使用内置函数,而不是使用采用Python编写的函数.通过使用运行列表操作的内置函数(例如map(),reduce(),filter())代替直接循环,可以把一些循环开销转移到C代码.向map,reduce,filter传送内置函数更会使性能得以提高.具有多重循环之时,只有最内层循环值得优化.优化多重循环时,旨在减少内存分配的次数.使最内层循环成为交互作用次数最少者应该有助于性能设计.使用局部变量会大大改善循环内部的处理时间.只要可能,在进入循环前把所有全局变量和属性搜索复制到局部变量.如果在嵌套循环内部使用诸如range(n)之类的结构方法,则在最外层循环外部把值域分配到一个局部变量并在循环定义中使用该变量将快速得多.

    yRange = range( 500 )
    
for  xItem  in  range( 100000 ):
        
for  yItem  in  xRange:
            
print  xItem,yItem

这里的另一种优化是使用xrange作为循环的x,因为100000项列表是一个相当大的列表.

yRange = range( 500 )
    
for  xItem  in  xRange( 100000 ):
        
for  yItem  in  yRange:
            
print  xItem,yItem

函数--Python的内置函数比采用纯Python语言编写的函数执行速度要快,因为内置函数是采用C语言编写的.map(),filter()以及reduce就是在性能上优于采用Python编写的函数的内置函数范例.还应了解,Python把函数名作为全局常数加以处理.既然如此,前面我们看到的名字空间搜索的整个概念同样适用于函数.如果可以选择的话,使用map()函数的隐含循环代替for循环要快得多.我在这里提到的循环的执行时间在很大程序上取决于传送了什么函数.传送Python函数没有传送内置函数(诸如在operator模块里的那些函数)那么快.一旦决定要测试例程的性能,就可以使用一个下文将要解释的简单概念.其方法是度量调用例程和完成其执行历经的时间.

在向自己的程序增加这些执行之后,就可以以此为基准并测试新型方法.注意由于我们必须调用time()函数,所以时间开销会有所增加.

首先,需要导入时间模块:

     import  time

其次,只需要开始例程之前和执行之后设置一个计时器.这可采用time.clock()函数完成.

    start_timer = time.clock()
    call_your_routine()
    end_timer
= time.clock()
    
print  end_timer-start_timer

代码优化是一门非常复杂的科学,并不仅仅局限于Python程序.有时在提高了一个地方性能的同时,又会使其他某个地方的性能降低.这里的意思是说,如果应用程序的处理时间看起来还可以,那就不要碰它.作者建议:实际性能问题导致应用程序产生不可忍受的运行瓶颈时,就设法优化程序代码.

Python Profile模块此工具可以帮助识别代码中的瓶颈问题.

另外介绍一下有用的资源:

http://wiki.python.org/moin/PythonSpeed/PerformanceTips


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值