在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
一条线。 简单。 没有例外。
dict
types有一个get
函数 ,如果字典中不存在该键,那么get
的第二个参数就是它应该返回的值。 类似的,还有setdefault
,如果key存在,则返回dict
的值,否则根据默认参数设置该值,然后返回默认参数。
您可以扩展list
types以具有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()
方法引发的StopIteration
exception ,表示没有更多的值。
那这个呢:
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)