注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

@fc_lamp

关注Web应用解决方案MySql/PHP/Python一盏名为"飞川"的灯~

 
 
 

日志

 
 

python代码性能优化  

2012-03-26 14:45:00|  分类: Web技术-Python |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

 1.使用内建函数:

    你可以用Python写出高效的代码,但很难击败内建函数. 经查证. 他们非常快速. list(),join(),split().......

   当对字符串可以使用正则表达式或者内置函数来处理的时候,选择内置函数。如 str.isalpha(),str.isdigit(),str.startswith(('x', 'yz')),str.endswith(('x', 'yz'))

对字符进行格式化比直接串联读取要快,因此要使用

out = "<html>%s%s%s%s</html>" % (head, prologue, query, tail),


不应使用

out = "<html>" + head + prologue + query + tail + "</html>" 


技巧:快速产生A-Z字母表

suzi = range(0,10)
zimu = [chr(x) for x in xrange(65,91)] #chr ascii码


2.使用join()连接字符串.

      你可以使用 "+" 来连接字符串. 但由于string在Python中是不可变的,每一个"+"操作都会创建一个新的字符串并复制旧内容. 常见用法是使用Python的数组模块单个的修改字符;当完成的时候,使用 join() 函数创建最终字符串.

#字符串处理

st = time()

lists = ['a','b','b','d','e','f','g','h','i','j','k','l','m','n']

s = ''

for i in xrange(1):

    for l in lists:

        s+=l #直使用"+" 没有join快

print time()-st

st = time()

s = ''

lists = dict.fromkeys(lists,True)

for i in xrange(1):

    #list处理应使用[xx for xx in xxx] 生成器方式

    s = ' '.join([x.upper() for x in lists])

print time()-st

#另外字符串格式化要好于字符串并接(+)



3. 使用Python多重赋值,交换变量
    这在Python中即优雅又快速:

      >>> x, y = y, x
      这样很慢:
      >>> temp = x
      >>> x = y
      >>> y = temp     


     

4. 尽量使用局部变量
    Python 检索局部变量比检索全局变量快. 这意味着,避免 "global" 关键字.

5. 尽量使用 "in"
      使用 "in" 关键字. 简洁而快速.

      >>> for key in sequence:
      >>>     print “found”


6. 使用延迟加载加速
      將 "import" 声明移入函数中,仅在需要的时候导入. 换句话说,如果某些模块不需马上使用,稍后导入他们. 例如,你不必在一开使就导入大量模块而加速程序启动. 该技术不能提高整体性能. 但它可以帮助你更均衡的分配模块的加载时间.

7. 为无限循环使用 "while 1"
    有时候在程序中你需一个无限循环.(例如一个监听套接字的实例) 尽管 "while true" 能完成同样的事, 但 "while 1" 是单步运算. 这招能提高你的Python性能.

       >>> while 1:
      >>>    #do stuff, faster with while 1
      >>> while True:

      >>>    # do stuff, slower with wile True



8.使用list comprehension
    从Python 2.0 开始,你可以使用 list comprehension 取代大量的 "for" 和 "while" 块. 使用List comprehension通常更快,Python解析器能在循环中发现它是一个可预测的模式而被优化.额外好处是,list comprehension更具可读性(函数式编程),并在大多数情况下,它可以节省一个额外的计数变量。例如,让我们计算1到10之间的偶数个数:

      >>> # the good way to iterate a range
      >>>evens = [ i for i in range(10) if i%2 == 0]
      >>> [0, 2, 4, 6, 8]
      >>> # the following is not so Pythonic
      >>> i = 0
      >>> evens = []
      >>> while i < 10:
      >>>    if i %2 == 0: evens.append(i)
      >>>    i += 1
      >>> [0, 2, 4, 6, 8]



9. 使用xrange()处理长序列:
    这样可为你节省大量的系统内存,因为xrange()在序列中每次调用只产生一个整数元素。而相反 range(),它將直接给你一个完整的元素列表,用于循环时会有不必要的开销。

10. 使用 Python generator:
      这也可以节省内存和提高性能。例如一个视频流,你可以一个一个字节块的发送,而不是整个流。例如,     

      >>> chunk = ( 1000 * i for i in xrange(1000))
      >>> chunk
      <generator object <genexpr> at 0x7f65d90dcaa0>
      >>> chunk.next()
      0
      >>> chunk.next()
      1000
      >>> chunk.next()
      2000


11. 了解itertools模块:
      该模块对迭代和组合是非常有效的。让我们生成一个列表[1,2,3]的所有排列组合,仅需三行Python代码:

      >>> import itertools
      >>> iter = itertools.permutations([1,2,3])
      >>> list(iter)
      [(1, 2, 3), (1, 3, 2), (2, 1, 3), (2, 3, 1), (3, 1, 2), (3, 2, 1)]



12. 学习bisect模块保持列表排序:
      这是一个免费的二分查找实现和快速插入有序序列的工具。也就是说,你可以使用:

      >>> import bisect
      >>> bisect.insort(list, element)


     你已將一个元素插入列表中, 而你不需要再次调用 sort() 来保持容器的排序, 因为这在长序列中这会非常昂贵.

13. 理解Python列表,实际上是一个数组:
      Python中的列表实现并不是以人们通常谈论的计算机科学中的普通单链表实现的。Python中的列表是一个数组。也就是说,你可以以常量时间O(1) 检索列表的某个元素,而不需要从头开始搜索。这有什么意义呢? Python开发人员使用列表对象insert()时, 需三思. 例如:>>> list.insert(0,item)
      在列表的前面插入一个元素效率不高, 因为列表中的所有后续下标不得不改变. 然而,您可以使用list.append()在列表的尾端有效添加元素. 挑先deque,如果你想快速的在两插入或时。它是快速的,因为在Python中的deque用双链表实现。不再多说。 :)

14. 使用dict 和 set 测试成员:

检查一个元素是在dicitonary或set是否存在 这在Python中非常快的。这是因为dict和set使用哈希表来实现。查找效率可以达到O(1)。因此,如果您需要经常检查成员,使用 set 或 dict做为你的容器.


#使用HASH 表 字典

from time import time

t = time()

lists = ['a','b','is','python','jason','hello','hill','with','phone','test',

 'dfdf','apple','pddf','ind','basic','none','baecr','var','bana','dd','wrd']

lists = dict.fromkeys(lists,True) #使用字典时间缩小一半

for i in xrange(1000000):

    if 'test' in lists:

        pass

print time() - t


#求数组交,并集的使用set

st = time()

lista = ['l','i','s','t']

listb = ['l','b','s','t']

for i in xrange(1):

    for a in lista:

        for b in listb:

            if a==b:

                pass

print time()-st #2.625 s 

 

st = time()

for i in xrange(1):

    s = list(set(lista)&set(listb))

print time() - st #1.86 


另外对于新加入字典的元素,如果没有值得话,应该使用默认值的方式,而不是循环判断:

#字典默认值的设置

from collections import defaultdict

s = 'asdfwfaw2edxwserwasdxcsc'

#提供默认值

cs = defaultdict(int)

for c in s:

    cs[c] +=1  #或者取使用cs[c] = cs.get(c, 0) +1

print dict(cs) 




15. 使用Schwartzian Transform 的 sort():

原生的list.sort()函数是非常快的。 Python会按自然顺序排序列表。有时,你需要非自然顺序的排序。例如,你要根据服务器位置排序的IP地址。 Python支持自定义的比较,你可以使用list.sort(CMP()),这会比list.sort()慢,因为增加了函数调用的开销。如果性能有问 题,你可以申请Guttman-Rosler Transform,基于Schwartzian Transform. 它只对实际的要用的算法有兴趣,它的简要工作原理是,你可以变换列表,并调用Python内置list.sort() - > 更快,而无需使用list.sort(CMP() )->慢。


16. Python装饰器缓存结果:
      “@”符号是Python的装饰语法。它不只用于追查,锁或日志。你可以装饰一个Python函数,记住调用结果供后续使用。这种技术被称为memoization的。下面是一个例子:

      >>> from functools import wraps
      >>> def memo(f):
      >>>    cache = { }
      >>>    @wraps(f)
      >>>    def  wrap(*arg):
      >>>        if arg not in cache: cache['arg'] = f(*arg)
      >>>        return cache['arg']

      >>>    return wrap


 

      我们也可以对 Fibonacci 函数使用装饰器:

      >>> @memo
      >>> def fib(i):
      >>>    if i < 2: return 1
      >>>    return fib(i-1) + fib(i-2)


   
     这里的关键思想是:增强函数(装饰)函数,记住每个已经计算的Fibonacci值;如果它们在缓存中,就不需要再计算了.

17. 理解Python的GIL(全局解释器锁):
      GIL是必要的,因为CPython的内存管理是非线程安全的。你不能简单地创建多个线程,并希望Python能在多核心的机器上运行得更快。这是因为 GIL將会防止多个原生线程同时执行Python字节码。换句话说,GIL將序列化您的所有线程。然而,您可以使用线程管理多个派生进程加速程序,这些程 序独立的运行于你的Python代码外。

18. 像熟悉文档一样的熟悉Python源代码:
      Python有些模块为了性能使用C实现。当性能至关重要而官方文档不足时,可以自由探索源代码。你可以找到底层的数据结构和算法。 Python的源码库就是一个很棒的地方:http://svn.python.org/view/python/trunk/Modules


19 if done is not None 比语句 if done != None 更快

 st = time()

d = None

for i in xrange(1000000):

    #if d != None: #0.125s

    if d is not None: #0.093s

        pass

print time()-st


20 使用级联比较 "x < y < z" 而不是 "x < y and y < z"


以上来自:1   http://www.oschina.net/question/1579_45822

                 2 http://www.ibm.com/developerworks/cn/linux/l-cn-python-optim/index.html

                 3 其它技巧: http://blog.jobbole.com/32748/

        

  评论这张
 
阅读(458)| 评论(1)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017