2015-12-02 66 views
4

我想知道是否有人有一個很好的乾淨的Pythonic和有效的技術來實現在結果中涉及同樣表達式的解析。 需要明確的是,考慮下面簡單的例子:具有相同功能的Python列表理解和警告

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

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

這將打印

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

證明F是大多數元素叫了兩聲。如果f有副作用,這很好,我們想要什麼,但是如果f是一些沒有副作用的昂貴操作,則重複調用是不可取的。但是,只有爲每個元素調用f一旦解決辦法似乎笨拙/詳細對我說:

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

即使是收縮成一條線

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

所以,任何人都可以拿出更好的東西?

+4

我認爲你的最後兩個代碼塊是一樣好。 – Amadan

+1

opt1。雙重理解(如嵌套); OPT2。理解+過濾器; OPT3。 memoize'f()' –

+1

我認爲中間生成器的方法是python可以提供的最好的東西。在理解中有一個'let'會很棒,但這不是haskell。 – bgusach

回答

2

可以使用filter()功能:

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

但是,這是我們所你最後的建議解決方案爲詳細。

+0

不需要中間列表,生成器應該也可以工作 – warvariuc

+1

這並不比OP的建議更清潔,並且可能因爲lambda調用而變得更慢。我會爲了簡單起見去堅持一個生成器+一個列表理解。 – bgusach

1

如何記憶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,withing您的通話網站的範圍有一次some_or_other()回報,「備忘錄」將內存垃圾收集的優勢,你不必擔心被傳遞給到v引用f()

由於它是本地的,備註大小限制1就足夠了。

在簡單情況下,你也可以memoize的f全球:

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

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

P.S. 'lru_cache()':[Python]版本3.2中的新增功能。 –

0

什麼安德烈斯·佩雷斯 - Albela H.說,除了使用map()內置功能:

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

你也可以看看itertools模塊,但我不確定它是否可以應用於此示例。在更復雜的情況下,儘管它可能提供解決方案。