概述
我们都知道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 y
list(yield_fun(xrange(1000)))
利用yield方法虽然并未使用LC,但也保证了每个函数执行一次。
对三种方法我分别进行了性能测试,下面是测试代码:
#!/usr/bin/python
# -*- coding: utf-8 -*-
# author : eclipse
# email : adooadoo@163.com
import time
def fun(n):
#print n,'is calculated!'
time.sleep(0.001)
return n*2+1
ran = 1000
a=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 y
list(yield_fun(xrange(ran)))
d=time.time()
print 'A:',b-a
print 'B:',c-b
print 'C:',d-c
结果如下:
A: 3.00797700882
B: 2.28105807304
C: 2.27167606354
我们可以看出第三种方法最好,但第二种方法和其差距并不是很大,这有点出乎我的意料,我分析原因,可能第二种方法中的第二个for是导致其速度降低的原因,相比较而言,我们只需要抛弃第一种方法就可以了。
值得注意的是,若注释掉
time.sleep(0.001)
这一句,当range范围很大时候,A方法的速度会快于B,这表明在函数重复执行和两层循环之间(也就是AB的不同处)存在权衡,并不是所有情况A都是劣于B的,值得欣慰的是,C方法速度还是最快的。下面结果是RAN为200000注释上一条代码的结果:
A: 0.0596971511841
B: 0.0742809772491
C: 0.0374338626862
最后
以上就是霸气西牛为你收集整理的list comprehension 函数复用及效率评估的全部内容,希望文章能够帮你解决list comprehension 函数复用及效率评估所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复