用于Python的list.index()函数,在没有找到任何内容时不会抛出异常

Yar*_*rin 62 python

list.index(x)如果该项不存在,Python会抛出异常.有没有更好的方法来做到这一点,不需要处理异常?

Ray*_*ger 78

如果你不关心匹配元素的位置,那么使用:

found = x in somelist
Run Code Online (Sandbox Code Playgroud)

如果你关心,那么使用带有条件表达式LBYL样式:

i = somelist.index(x) if x in somelist else None
Run Code Online (Sandbox Code Playgroud)

  • 但这种方法不是比运行`index()`慢得多吗?毕竟你必须看两次:一次是存在,一次是索引.这就是为什么C++容器没有`exists()`,只有`find()`. (11认同)
  • 正如@frans所说,这需要两次查找,但这是另一种可以在一次传递中完成工作的方法:`i = next((i代表i,t代表枚举(somelist),如果x == t),None) ` (5认同)
  • 感谢Raymond,发现这是最简洁的答案(同样,将默认值从-1更改为None,因为-1是有效的列表索引) (2认同)
  • 谢谢雷蒙德,LBYL 对我来说是新的参考。 (2认同)
  • @AXO 尽管这是一次传递,但对于内置类型来说它会更慢,因为查找是由 Python 而不是 C 代码执行的。 (2认同)

nea*_*mcb 11

TL; DR:例外是您的朋友,并且是所述问题的最佳方法。
请求宽恕比许可更容易(EAFP)

OP 在评论中澄清说,对于他们的用例,知道索引是什么实际上并不重要。正如公认的答案所指出的,x in somelist如果您不在乎,使用是最好的答案。

但我会假设,正如最初的问题所暗示的那样,您确实关心索引是什么。在这种情况下,我会注意到所有其他解决方案都需要扫描列表两次,这会带来很大的性能损失。

此外,正如可敬的雷蒙德·赫廷格 (Raymond Hettinger) 在评论中所写

即使我们有 list.find 返回 -1,您仍然需要测试以查看 i == -1 并采取一些措施。

因此,我将推翻原始问题中应该避免异常的假设。我建议例外是你的朋友。它们没什么好害怕的,它们也不是低效的,事实上你需要熟悉它们才能编写好的代码。

所以我认为最好的答案是简单地使用 try-except 方法:

try:
    i = somelist.index(x) 
except ValueError:
    # deal with it
Run Code Online (Sandbox Code Playgroud)

处理它”只是意味着做你需要做的事情:将 i 设置为哨兵值,引发你自己的异常,遵循不同的代码分支等。

这是为什么 Python 原则比许可更容易请求宽恕(EAFP)有意义的一个例子,与跳跃前先看(LBYL)的 if-then-else 风格形成对比

  • 我笑得很大声。有时洞察力不会持久。我只是在上面发表评论,没有注意到我在两年前就已经写下了答案。只有当我试图投票赞成我自己的答案时,才提示我。 (8认同)
  • 例外是昂贵的 (6认同)
  • @AndrewScottEvans 你可能正在考虑其他语言。Python 不运行本机机器代码,因此没有必要将异常实现为硬件中断。在 C API 中,异常是 NULL 返回值和全局设置的(每个线程)异常对象:https://docs.python.org/3/c-api/exceptions.html 可以说,动态的整个概念类型化虚拟机本身就会影响性能,但考虑到这一点,Python 异常没有理由从根本上比任何其他 Python 语句慢或快。 (4认同)
  • 如此真实!我以为我遇到了这个问题,起初认为其他解决方案之一很好。然后我再次查看我的代码,并意识到使用 *try... except* 会更加快速和自然,因为当然我仍然需要*处理它*.... (3认同)

Mar*_*ers 6

编写一个满足您需要的函数:

def find_in_iterable(x, iterable):
    for i, item in enumerate(iterable):
        if item == x:
            return i
    return None
Run Code Online (Sandbox Code Playgroud)

如果您只需要知道该项目是否存在,而不需要知道索引,您可以使用in

x in yourlist
Run Code Online (Sandbox Code Playgroud)

  • PS“-1”是有效的列表索引 - 您需要返回“None” (4认同)

A.H*_*A.H 6

为列表实现自己的索引?

class mylist(list):
  def index_withoutexception(self,i):
    try:
        return self.index(i)
    except:
        return -1
Run Code Online (Sandbox Code Playgroud)

因此,您可以使用list,并使用index2,在出现错误时返回所需内容.

你可以像这样使用它:

  l = mylist([1,2,3,4,5]) # This is the only difference with a real list
  l.append(4) # l is a list.
  l.index_withoutexception(19) # return -1 or what you want
Run Code Online (Sandbox Code Playgroud)

  • 另外 - 我并不积极,但在我看来,如果目标是避免引发异常(如果经常发生,代价高昂),那么这并不能实现它。它将返回 -1,但内部仍然会引发异常,这仍然是昂贵的。 (2认同)