在python中处理list.index(可能不存在)的最佳方法是什么?

我有这样的代码:

thing_index = thing_list.index(thing) otherfunction(thing_list, thing_index) 

好吧,这是简化,但你明白了。 现在thing可能不会在列表中,在这种情况下,我想传递-1作为thing_index 。 在其他语言中,这是你所期望的index()返回,如果它找不到该元素。 实际上它会抛出一个ValueError

我可以这样做:

 try: thing_index = thing_list.index(thing) except ValueError: thing_index = -1 otherfunction(thing_list, thing_index) 

但是,这感觉很脏,再加上我不知道ValueError是否可以因为其他原因而被提出。 我提出了基于生成器函数的以下解决scheme,但似乎有点复杂:

 thing_index = ( [(i for i in xrange(len(thing_list)) if thing_list[i]==thing)] or [-1] )[0] 

有一个更清洁的方式来实现相同的事情? 我们假设列表没有sorting。

使用try-except从句没有什么“脏”的东西。 这是pythonic的方式。 ValueError只会被.index方法提出,因为这是你在那里唯一的代码!

回答评论:
在Python中, 请求宽恕比获取权限的理念更容易没有 index也不会引发这种types的错误。 不是我能想到的。

 thing_index = thing_list.index(elem) if elem in thing_list else -1 

一条线。 简单。 没有例外。

dicttypes有一个get函数 ,如果字典中不存在该键,那么get的第二个参数就是它应该返回的值。 类似的,还有setdefault ,如果key存在,则返回dict的值,否则根据默认参数设置该值,然后返回默认参数。

您可以扩展listtypes以具有getindexdefault方法。

 class SuperDuperList(list): def getindexdefault(self, elem, default): try: thing_index = self.index(elem) return thing_index except ValueError: return default 

然后可以使用,如:

 mylist = SuperDuperList([0,1,2]) index = mylist.getindexdefault( 'asdf', -1 ) 

您的代码使用ValueError没有任何问题。 如果您想避免例外情况,那么这里还有另外一种方法:

 thing_index = next((i for i, x in enumerate(thing_list) if x == thing), -1) 

这个问题是语言哲学之一。 例如在Java中,一直存在这样的传统,即exception只能用于发生错误时的“特殊情况”,而不是用于stream量控制 。 一开始这是出于性能方面的原因,因为Javaexception很慢,但现在这已经成为公认的风格。

相比之下,Python总是使用exception来指示正常的程序stream,就像我们在这里讨论的那样引发ValueError一样。 在Python风格上没有什么“脏”的东西,还有更多来自哪里。 一个更常见的例子是迭代器的next()方法引发的StopIterationexception ,表示没有更多的值。

那这个呢:

 otherfunction(thing_collection, thing) 

而不是像function接口中的列表索引那样暴露依赖实现的东西,传递集合和事物,让其他函数处理“testing成员资格”问题。 如果其他函数被写入集合types不可知的,那么它可能会从以下开始:

 if thing in thing_collection: ... proceed with operation on thing 

这将工作,如果thing_collection是一个列表,元组,集或字典。

这可能比:

 if thing_index != MAGIC_VALUE_INDICATING_NOT_A_MEMBER: 

这是你已经在其他function的代码。

我对列表上的“.index()”方法有同样的问题。 我没有问题,它引发了一个exception,但我坚决不同意它是一个非描述性的ValueError的事实。 我可以理解,如果它会是一个IndexError,虽然。

我可以看到为什么返回“-1”也是一个问题,因为它是一个Python中的有效索引。 但实际上,我从来不希望“.index()”方法返回一个负数。

这里是一个单行(确定,这是一个相当长的一行…),完全通过列表一次,并返回“无”,如果该项目没有find。 如果你愿意的话,重写它返回-1是微不足道的。

 indexOf = lambda list, thing: \ reduce(lambda acc, (idx, elem): \ idx if (acc is None) and elem == thing else acc, list, None) 

如何使用:

 >>> indexOf([1,2,3], 4) >>> >>> indexOf([1,2,3], 1) 0 >>> 

我不知道你为什么觉得这是肮脏的…因为例外? 如果你想要一个oneliner,这里是:

 thing_index = thing_list.index(elem) if thing_list.count(elem) else -1 

但我会build议不要使用它; 我认为罗斯·罗杰斯(Ross Rogers)的解决scheme是最好的,用一个对象来封装你想要的行为,不要试图以可读性为代价推动语言达到极限。

我会build议:

 if thing in thing_list: list_index = -1 else: list_index = thing_list.index(thing)