Python 的 list.index() 函数,当没有找到时不会抛出异常
Posted
技术标签:
【中文标题】Python 的 list.index() 函数,当没有找到时不会抛出异常【英文标题】:list.index() function for Python that doesn't throw exception when nothing found 【发布时间】:2012-01-02 02:19:15 【问题描述】:如果项目不存在,Python 的 list.index(x)
会引发异常。有没有更好的不需要处理异常的方法?
【问题讨论】:
视情况而定。你关心它在哪里吗? 最好的方法取决于你在什么都找不到的情况下该怎么做。即使我们有返回 -1 的 list.find,您仍然需要测试以查看是否为i == -1
并采取一些措施。
Raymond- 似乎应该由我来决定我的代码是否可以处理 None 索引,而不是强制异常。但是,我仍在学习如何成为 Pythonic...
Why list doesn't have safe "get" method like dictionary?的可能重复
@yarin,正如我在回答中澄清的那样,如果您不需要索引,in
关键字就是您所需要的。但如果你这样做了,我认为 Raymond 有一个很好的观点,例外是解决这个问题的最佳方法。
【参考方案1】:
如果你不关心匹配元素在哪里,那么使用:
found = x in somelist
如果您在乎,请使用LBYL 样式和conditional expression:
i = somelist.index(x) if x in somelist else None
【讨论】:
感谢 Raymond,发现这是最简洁的答案(同样,将默认值从 -1 更改为 None,因为 -1 是有效的列表索引) 谢谢雷蒙德,LBYL 对我来说是新的参考。 但是这种方法不是比只运行index()
慢很多吗?毕竟你必须看两次:一次是为了存在,一次是为了索引。这就是为什么 C++ 容器没有exists()
,只有find()
。
正如@frans 所说,这需要两次查找,但这是另一种可以一次性完成工作的方法:i = next((i for i, t in enumerate(somelist) if x == t), None)
@AXO 虽然是一次性的,但是对于内置类型来说它会更慢,因为查找是由 Python 而不是 C 代码执行的。【参考方案2】:
TL;DR:例外是您的朋友,也是解决上述问题的最佳方法。 请求宽恕比请求许可更容易 (EAFP)
OP 在评论中澄清说,对于他们的用例,知道索引是什么实际上并不重要。正如公认的答案所指出的,如果您不在乎,使用x in somelist
是最好的答案。
但我会假设,正如最初的问题所暗示的那样,您确实关心索引是什么。在这种情况下,我会注意到所有其他解决方案都需要扫描列表两次,这会带来很大的性能损失。
此外,正如可敬的 Raymond Hettinger 在评论中所写的那样
即使我们有返回 -1 的 list.find,您仍然需要测试 i == -1 并采取一些措施。
因此,我将推翻原始问题中应避免异常的假设。我建议例外是你的朋友。它们没什么好怕的,它们也不是低效的,事实上你需要熟悉它们才能写出好的代码。
所以我认为最好的答案是简单地使用 try-except 方法:
try:
i = somelist.index(x)
except ValueError:
# deal with it
“处理它”只是意味着做你需要做的事情:将 i 设置为哨兵值,引发你自己的异常,遵循不同的代码分支,等等。
这是 Python 原理 Easier to ask for forgiveness than permission (EAFP) 与 Look before you leap (LBYL) 的 if-then-else 风格形成对比的一个示例
【讨论】:
如此真实!我以为我遇到了这个问题,起初认为其他解决方案之一很好。然后我再次查看我的代码,并意识到使用 try...except 会更快更自然,因为当然我仍然必须处理它。 ... 我笑出声来。有时洞察力不会持久。我只是在上面发表了评论,没有注意到我在 2 年前就已经写了答案。只有当我试图投票给自己的答案时,我才知道。 这真是太搞笑了! 例外是昂贵的 @AndrewScottEvans 您可能正在考虑其他语言。 Python 不运行本机机器代码,因此没有必要将异常实现为硬件中断。在 C API 中,异常是 NULL 返回值和全局设置(每个线程)异常对象:docs.python.org/3/c-api/exceptions.html 可以说,动态类型虚拟机的整个概念本身就是性能损失,但鉴于此,没有理由使 Python 异常从根本上比任何其他 Python 语句更慢或更快。【参考方案3】:实现您自己的列表索引?
class mylist(list):
def index_withoutexception(self,i):
try:
return self.index(i)
except:
return -1
因此,您可以使用列表,并使用您的 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) == list
在这里是 False
。
另外 - 我并不积极,但在我看来,如果目标是避免引发异常(如果经常发生这种情况会很昂贵),那么这并没有实现。它将返回 -1,但在内部仍会引发异常,但代价仍然很高。【参考方案4】:
编写一个满足你需要的函数:
def find_in_iterable(x, iterable):
for i, item in enumerate(iterable):
if item == x:
return i
return None
如果只需要知道item是否存在,而不需要知道索引,可以使用in
:
x in yourlist
【讨论】:
谢谢-但我希望得到一些预先包装好的东西 PS '-1' 是一个有效的列表索引 - 您需要返回 'None' @Yarin:我选择 -1 的原因是为了与现有的 Python 习惯用法保持一致,例如'abc'.find('x') == -1
,但 None
也可以。我会更新我的答案。
是的,奇怪的是 .find() 这样做 - 似乎与 Python 的负索引不一致。【参考方案5】:
是的,有。你可以例如。做类似的事情:
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
,但它可以是您认为合适的任何东西。
【讨论】:
【参考方案6】:如果你不关心它在序列中的位置,只关心它的存在,那么使用in
运算符。否则,编写一个重构异常处理的函数。
def inlist(needle, haystack):
try:
return haystack.index(needle)
except ...:
return -1
【讨论】:
我发布了一个答案,使用in
检查是否存在并最终返回索引,但我看到您知道该方法并决定使用处理可能引发的异常。我的问题是:你为什么选择捕获异常而不是首先检查haystack
是否存在needle
?有什么理由吗?
@Tadeck:因为不成文的 Python 规则,“请求原谅比请求许可更容易”。
谢谢 :) 我刚刚在 Python 词汇表上找到了它,其中 EAFP (Easier to Ask for Forgiveness than for Permission) 显示为与 LBYL (Look Before You Leap) 相反的东西。确实,EAFP 已被命名为常见的 Python 编码风格,所以它并不是那么不成文:) 再次感谢!
您实际上并不需要 except ...:
行中的 ...
。【参考方案7】:
我喜欢使用Web2py's List 类,在其gluon 包的存储模块中找到。 storage 模块提供类列表 (List) 和类字典 (Storage) 数据结构,在找不到元素时不会引发错误。
首先下载web2py's source,然后将gluon包文件夹复制粘贴到你的python安装的站点包中。
现在试试吧:
>>> 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
【参考方案8】:
没有内置的方法可以做你想做的事。
这是一篇可以帮助你的好帖子:Why list doesn't have safe "get" method like dictionary?
【讨论】:
那篇文章是关于数组索引的,有IndexError: list index out of range
问题,而不是这里描述的index()
方法和ValueError: <value> is not in list
问题。【参考方案9】:
希望对你有帮助
lst= ','.join('qwerty').split(',') # create list
i='a' #srch string
lst.index(i) if i in lst else None
【讨论】:
以上是关于Python 的 list.index() 函数,当没有找到时不会抛出异常的主要内容,如果未能解决你的问题,请参考以下文章