2011-08-18 158 views
27

我使用發電機來執行列表中搜索喜歡這個簡單的例子:如何讓Python生成器返回None而不是StopIteration?

>>> a = [1,2,3,4] 
>>> (i for i, v in enumerate(a) if v == 4).next() 
3 

(只是幀的例子了一下,我使用很長的列表相比,上面的一個,並且條目是更復雜一點比int。我這樣做,這樣我每次搜索它們)

所以整個列表不會被遍歷現在,如果我反而改變,要i == 666,它會返回一個StopIteration因爲它可以」 t在a找到任何666條目。

我該如何讓它返回None?我當然可以將它包裝在try ... except條款中,但是有更多的pythonic方法可以做到嗎?

+0

我能問你爲什麼使用發電機來搜索的東西呢? –

+0

如果您搜索已經過去的東西,您會發生什麼?爲什麼不使用更'pythonic'的方式,比如'如果我在a:...'中? –

+0

@Manny D,如果你想得到找到的物品的索引,「如果我在a」中沒有幫助。 – senderle

回答

70

如果您正在使用Python 2.6+,你應該使用next內置的功能,而不是next方法(這與__next__在3.X取代)。該next內置有一個可選的默認參數,返回如果迭代被耗盡,而不是提高StopIteration

next((i for i, v in enumerate(a) if i == 666), None) 
+1

+1,這是做到這一點的最好方法。 – senderle

+0

我不知道內置函數已經改變。這使得它變得更容易 – c00kiemonster

7

你可以鏈(無)發電機:

from itertools import chain 
a = [1,2,3,4] 
print chain((i for i, v in enumerate(a) if v == 6), (None,)).next() 

但我認爲a.index(2)將不會穿越的完整列表,當發現2,搜索完成。您可以測試此:

>>> timeit.timeit("a.index(0)", "a=range(10)") 
0.19335955439601094 
>>> timeit.timeit("a.index(99)", "a=range(100)") 
2.1938486138533335 
+1

連鎖事情非常聰明,沒有想到那個。是的,index()並不差,但在我的真實情況下,我不能真正使用它,因爲列表條目是對象而不是變量。編輯:我比較對象屬性和其他有趣的東西,而不是隻是尋找對象本身。 – c00kiemonster

+1

對不起,這是一個過於複雜的解決方案。 「next」內置函數已經以一種簡潔的方式提供了這個功能。 @ c00kiemonster,我認爲你應該使用(並接受)[zeekay的答案](http://stackoverflow.com/questions/7102050/how-can-i-get-a-python-generator-to-return-none-rather -than-StopIteration異常/ 7102204#7102204)。 – senderle

+0

不用擔心,找出Python中較新的東西的好方法,如果沒有別的... – c00kiemonster

相關問題