Python的list.index()函数在找不到任何内容时不引发异常


76

list.index(x)如果该项不存在,Python会引发异常。有没有更好的方式来执行此操作而无需处理异常?


1
依靠。你关心其中,它是什么?
伊格纳西奥·巴斯克斯

2
最好的方法取决于在什么都没发现的情况下该做什么。即使我们的list.find返回了-1,您仍然需要进行测试以查看是否i == -1采取了某些措施。
Raymond Hettinger

2
Raymond-似乎应该由我决定我的代码是否可以处理None索引,而不是强制执行异常。但是后来,我仍在学习如何成为Pythonic ...
Yarin


正如我在回答中所阐明的,@ yarin如果不需要索引,则只需要in关键字。但是,如果您这样做,我认为雷蒙德(Raymond)有一个好处,而例外是解决此问题的最佳方法。
nealmcb

Answers:


93

如果您不在乎匹配元素在哪里,请使用:

found = x in somelist

如果您确实需要,请使用带有条件表达式LBYL样式:

i = somelist.index(x) if x in somelist else None

2
感谢Raymond,发现这是最简洁的答案(再次,将默认值从-1更改为None,因为-1是有效的列表索引)
Yarin

1
感谢Raymond,LBYL对我来说是新参考。
Burhan Khalid

14
但是,这种方法难道不是比跑步慢得多index()吗?毕竟,您必须看两次:一次是为了存在,一次是为了索引。这就是为什么C ++的容器没有exists(),只find()
frans

9
正如@frans所说,这需要两次查找,但这是可以一次性完成任务的另一种方式:i = next((i for i, t in enumerate(somelist) if x == t), None)
AXO

@AXO即使通过了一次,但对于内置类型它却会变慢,因为查找是由Python而不是C代码执行的。
ivan_pozdeev

7

实现您自己的列表索引?

class mylist(list):
  def index_withoutexception(self,i):
    try:
        return self.index(i)
    except:
        return -1

因此,您可以使用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

当心,因为这可能会破坏一些代码:type(l) == listFalse这里。
bfontaine 2014年

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

6

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

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

这是一个为什么Python原理比请求更容易获得宽恕(EAFP)有意义的例子,这与“先飞看(LBYL)”的if-then-else风格形成对比


1
如此真实!我以为我遇到了这个问题,一开始以为其他解决方案中的一个很好。然后我再次查看了我的代码,意识到使用try ... except会更加快捷自然,因为当然我仍然必须处理它..
nealmcb

1
我在大声笑。有时候,见解不会持久。我只是在上面发表评论,而没有注意到我是2年前写过答案的。只有当我试图对自己的答案投票时,我才有线索
。– nealmcb

这绝对好笑!
T_M

4

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

def find_in_iterable(x, iterable):
    for i, item in enumerate(iterable):
        if item == x:
            return i
    return None

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

x in yourlist

谢谢,但我希望预先包装好东西
Yarin

4
PS“-1”是一个有效的列表指数-你需要返回“无”
Yarin

@Yarin:之所以选择-1是为了与现有的Python习惯用法保持一致,例如'abc'.find('x') == -1,但None也可以使用。我将更新我的答案。
马克·拜尔斯

1
是的,.find()做到这一点很奇怪-似乎与Python的负索引不一致。
Yarin

3

就在这里。您可以例如。做类似的事情:

test = lambda l, e: l.index(e) if e in l else None

像这样工作:

>>> a = ['a', 'b', 'c', 'g', 'c']
>>> test(a, 'b')
1
>>> test(a, 'c')
2
>>> test(a, 't')
None

因此,基本上,test() 它将返回给定列表(第一个参数)中元素(第二个参数)的索引除非尚未找到(在这种情况下,它将返回None,但可以是您认为合适的任何东西)。


1

如果您不在乎序列中的位置,只需关心它的存在,然后使用in运算符。否则,编写一个重构异常处理的函数。

def inlist(needle, haystack):
  try:
    return haystack.index(needle)
  except ...:
    return -1

我已经发布了一个答案,该答案使用来检查存在性in并最终返回索引,但是我看到您知道该方法,因此决定使用可能引发的处理异常。我的问题是:为什么您选择捕获异常而不是首先检查haystack是否存在needle?有什么理由吗?
塔德克

@Tadeck:由于Python规则不完整,“请求宽恕比允许许可容易”。
伊格纳西奥·巴斯克斯

1
谢谢:)我刚刚发现它的Python词汇,其中EAFP(更容易原谅询问比许可)显示为相反的东西LBYL(三思而后行)。的确,EAFP已经被命名为通用的Python编码风格,所以它并不是那么不成文:)再次感谢!
塔德克

你并不真正需要...except ...:线。
swdev

1

希望这可以帮助

lst= ','.join('qwerty').split(',') # create list
i='a'  #srch string
lst.index(i) if i in lst else None


0

我喜欢使用Web2py的 List类,该类位于其gluon软件包的存储模块中。存储模块提供类似列表(List)和类似字典(Storage)的数据结构,当找不到元素时,它们不会引发错误。

首先下载web2py的source,然后将gluon package文件夹复制粘贴到python安装的site-packages中。

现在尝试一下:

>>> from gluon.storage import List
>>> L = List(['a','b','c'])
>>> print L(2)
c
>>> print L(3) #No IndexError!
None

注意,它也可以像常规列表一样运行:

>>> print L[3]

Traceback (most recent call last):
File "<pyshell#4>", line 1, in <module>
l[3]
IndexError: list index out of range

好主意,谢谢。)def __call__(self, idx, df=None): return self[idx] if 0<=idx<len(self) else df
Winand 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.