list comprehension 函数复用及效率评估

来源:互联网 发布:淘宝达人如何赚钱 编辑:程序博客网 时间:2024/06/03 20:07

我们都知道python的list comprehension会使得执行效率更高,但在list comprehension中函数使用上会存在多次调用问题。

比如,我定义如下函数:

def square(n):     print n,'is calculated!'    #time.sleep(0.001)    return n*2+1


我想统计10以内上述函数结果为3的倍数的list,可以写如下的list comprehension:

[square(x) for x in xrange(10) if fun(x)%3 == 0]

打印输出如下:

0 is caculated!1 is caculated!1 is caculated!2 is caculated!3 is caculated!4 is caculated!4 is caculated!5 is caculated!6 is caculated!7 is caculated!7 is caculated!8 is caculated!9 is caculated!

我们可以非常明显的看出,在满足if条件后fun方法执行了两次,这显然从效率上有所降低,在SO搜索相关问题后(http://stackoverflow.com/questions/11608238/is-it-possible-to-add-a-where-clause-with-list-comprehension)发现有如下解决方案:

[y for x in xrange(10) for y in [fun(x)] if y%3 == 0]
利用临时元素y和临时列表[fun(x)],我们就可以对函数进行重复使用

def yield_fun(iterable):    for x in iterable:        y = fun(x)        if y % 3 == 0:            yield ylist(yield_fun(xrange(1000)))
利用yield方法虽然并未使用LC,但也保证了每个函数执行一次

对三种方法我分别进行了性能测试,下面是测试代码:

#!/usr/bin/python# -*- coding: utf-8 -*-# author  : eclipse# email   : adooadoo@163.comimport timedef fun(n):     #print n,'is calculated!'    time.sleep(0.001)    return n*2+1ran = 1000a=time.time()  [fun(x) for x in xrange(ran) if fun(x)%3 == 0]b=time.time()  [y for x in xrange(ran) for y in [fun(x)] if y%3 == 0]c=time.time()  def yield_fun(iterable):    for x in iterable:        y = square(x)        if y % 3 == 0:            yield ylist(yield_fun(xrange(ran)))d=time.time()  print 'A:',b-aprint 'B:',c-bprint 'C:',d-c

结果如下:

A: 3.00797700882B: 2.28105807304C: 2.27167606354

我们可以看出第三种方法最好,但第二种方法和其差距并不是很大,这有点出乎我的意料,我分析原因,可能第二种方法中的第二个for是导致其速度降低的原因,相比较而言,我们只需要抛弃第一种方法就可以了。

值得注意的是,若注释掉

time.sleep(0.001)

这一句,当range范围很大时候,A方法的速度会快于B,这表明在函数重复执行和两层循环之间(也就是AB的不同处)存在权衡,并不是所有情况A都是劣于B的,值得欣慰的是,C方法速度还是最快的。下面结果是RAN为200000注释上一条代码的结果:

A: 0.0596971511841B: 0.0742809772491C: 0.0374338626862




0 0