简体   繁体   English

Python列表理解在guard和result中具有相同的功能

[英]Python list comprehension with same function in guard and result

I was wondering if someone has a nice clean Pythonic and effective technique for implementing comprehensions that involve the same expression in the guard as in the result. 我想知道是否有人有一个很好的干净Pythonic和有效的技术来实现在结果中涉及保护中相同表达的理解。 To be clear, consider the following simple example: 需要说明的是,请考虑以下简单示例:

def f(a):
    print "Calling", a
    return a + 1

print [ f(v) for v in xrange(3) if f(v) > 1 ]

This will print 这将打印

Calling 0
Calling 1
Calling 1
Calling 2
Calling 2
[2, 3]

proving that f is called twice for most elements. 证明f对于大多数元素被调用两次。 This is fine and what we want if f has side-effects, but if f is some expensive operation without side-effects, the duplicate call is not desirable. 这很好,如果f有副作用,我们想要什么,但如果f是一些没有副作用的昂贵操作,重复调用是不可取的。 But the solution that only calls f once for each element seems clumsy/verbose to me: 但是对于每个元素只调用f一次的解决方案对我来说似乎笨拙/冗长:

intermediate = ( f(v) for v in xrange(3) ) 
print [ r for r in intermediate if r > 1 ]

even if it is contracted into one line 即使它被收缩成一条线

print [ r for r in ( f(v) for v in xrange(3) ) if r > 1 ]

So, can anyone come up with something better? 那么,任何人都能想出更好的东西吗?

You can use the filter() function: 您可以使用filter()函数:

filter(lambda x: x > 1, [ f(v) for v in xrange(3)])

But that's about as verbose as your last suggested solution. 但这与您上次建议的解决方案一样冗长。

How about memoizing f , eg:? 如何记忆f ,例如:?

def f(...): ...

def some_or_other():
    f = functools.lru_cache(1)(f)
    [ f(v) for v in xrange(3) if f(v) > 1 ]

Memoizing locally, withing the scope of your call site has the advantage that once some_or_other() returns, "memo" memory will be garbage collected, and you don't have to worry about references to v that were passed to f() . 在本地进行记忆,具有调用站点的范围具有以下优点:一旦some_or_other()返回,“memo”内存将被垃圾收集,并且您不必担心传递给f()v引用。

Since it's local, memo size limit 1 is sufficient. 由于它是本地的,备忘录大小限制1就足够了。

In the simple case, you can also memoize f globally: 在简单的情况下,您还可以全局记忆f

@functools.lru_cache()
def f(...): ...

[ f(v) for v in xrange(3) if f(v) > 1 ]

What Andrés Pérez-Albela H. said, except use map() built-in function: 什么AndrésPérez-Albela H.说,除了使用map()内置函数:

filter(lambda x: x > 1, map(f, xrange(3)))

You could also look at itertools module, but I'm not sure if it can be applied to this example. 您还可以查看itertools模块,但我不确定它是否可以应用于此示例。 In more complex situations though it may offer a solution. 在更复杂的情况下,它可能提供解决方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM