防止列表理解中的多个调用

时间:2015-07-15 22:12:41

标签: python list-comprehension

使用以下作为示例,我们可以看到x.giveMyNum()将被调用4次 - 3次以检查myNum的值,并且一次构建要返回的列表。你可能只希望它被调用3次,因为它是一个纯函数,它的价值不会发生变化。

列表理解版本:

class test(object):
    def __init__(self,myNum):
        self.myNum=myNum
    def giveMyNum(self):
        print "giving"
        return self.myNum
q=[test(x) for x in range(3)]
print [x.giveMyNum() for x in q if x.giveMyNum()>1]

我知道你可以做这样的事情来解决它:

ret=[]
for x in q:
    k=x.giveMyNum()
    if k>1:
        ret.append(k)

但有没有办法阻止列表理解中的额外调用?

我不需要保留中间值。

2 个答案:

答案 0 :(得分:3)

您可以将它与生成器结合使用,但我会坚持使用常规循环。

print([n for n in (x.giveMyNum() for x in q) if n  > 1 ])

如果您喜欢功能代码,可以使用python2映射或itertools.imap

print([n for n in map(test.giveMyNum, q) if n > 1 ])

使用python2和imap比gen exp:

更快
In [8]: q = [test(x) for x in range(10000)]

In [9]: timeit [ n for n in imap(test.giveMyNum, q) if n > 1]
1000 loops, best of 3: 1.94 ms per loop

In [10]: timeit [n for n in (x.giveMyNum() for x in q) if n  > 1 ]
100 loops, best of 3: 2.56 ms per loop

使用python3的地图也更快:

In [2]: timeit [ n for n in map(test.giveMyNum, q) if n > 1]
100 loops, best of 3: 2.23 ms per loop

In [3]: timeit [n for n in (x.giveMyNum() for x in q) if n  > 1 ]
100 loops, best of 3: 2.93 ms per loop

常规循环的时间并调用方法:

In [8]: timeit [x.giveMyNum() for x in q if x.giveMyNum()>1]
100 loops, best of 3: 3.59 ms per loop

In [9]: %%timeit
ret=[]
for x in q:
    k=x.giveMyNum()
    if k>1:
        ret.append(k)
   ...: 
100 loops, best of 3: 2.67 ms per loop

Python3:

In [2]: %%timeit
ret=[]
for x in q:
    k=x.giveMyNum()
    if k>1:
        ret.append(k)
   ...: 
100 loops, best of 3: 2.84 ms per loop

In [3]: timeit [x.giveMyNum() for x in q if x.giveMyNum()>1]

100 loops, best of 3: 4.08 ms per loop

答案 1 :(得分:3)

这是可能的,但不是很可读...

print [y for y in (x.giveMyNum() for x in q) if y > 1]

所以除非giveMyNum()慢或不纯,否则我会避免它。