【问题标题】:How can I get a Python generator to return None rather than StopIteration?如何让 Python 生成器返回 None 而不是 StopIteration?
【发布时间】:2011-10-29 10:41:03
【问题描述】:

我正在使用生成器在列表中执行搜索,例如这个简单的示例:

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

(只是为了举例说明,与上面的列表相比,我使用的列表要长得多,并且条目比int 复杂一点。我这样做是为了整个列表不会'每次我搜索它们时都不会被遍历)

现在,如果我将其改为i == 666,它将返回一个StopIteration,因为它在a 中找不到任何666 条目。

我怎样才能让它返回None?我当然可以将它包装在 try ... except 子句中,但是有没有更 Pythonic 的方式来做到这一点?

【问题讨论】:

  • 我能问一下你为什么使用生成器来搜索东西吗?
  • 如果你搜索你已经忽略的东西,你期望会发生什么?为什么不直接使用像if i in a: ... 这样更“pythonic”的方式?
  • @Manny D, if i in a 如果您想获取找到的项目的索引,则无济于事。
  • @senderle 你可以使用a.index(i)。你不知道使用enumerate 的好处,没错,但我真的明白你为什么要使用生成器来搜索列表。
  • @Manny D,true,但仅适用于定义了 index 方法的迭代。此外,如果您想测试除简单相等之外的其他内容(例如,如果您想查找 > 5 的第一项),那么 index 将无济于事。不过,您是对的,在 c00kiemonster 给出的具体示例中,index 是更明智的方法。

标签: python exception generator stopiteration


【解决方案1】:

如果您使用的是 Python 2.6+,则应使用 next 内置函数,而不是 next 方法(在 3.x 中已替换为 __next__)。 next 内置函数接受一个可选的默认参数以在迭代器耗尽时返回,而不是引发 StopIteration

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

【讨论】:

  • 不知道内置函数变了。这肯定会让事情变得容易得多
  • 感谢您的回答。但我正在使用Python 3.6.3,它也适用于我的项目。
【解决方案2】:

您可以使用 (None,) 链接生成器:

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

【讨论】:

  • 链条的东西很聪明,没想到那个。是的index() 还不错,但在我的实际情况下,我不能真正使用它,因为列表条目是对象而不是变量。编辑:我正在比较对象属性和其他有趣的东西,而不仅仅是寻找对象本身。
  • 很抱歉,这是一个过于复杂的解决方案。 next 内置函数已经以简洁的方式提供了此功能。 @c00kiemonster,我认为你应该使用(并接受)zeekay's answer
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-07-03
  • 2018-06-25
  • 1970-01-01
  • 2014-03-17
  • 2023-03-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多