2011-08-18 160 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

相关问题