标签归档:indexoutofboundsexception

为什么列表没有像字典一样安全的“获取”方法?

问题:为什么列表没有像字典一样安全的“获取”方法?

为什么列表没有像字典一样安全的“获取”方法?

>>> d = {'a':'b'}
>>> d['a']
'b'
>>> d['c']
KeyError: 'c'
>>> d.get('c', 'fail')
'fail'

>>> l = [1]
>>> l[10]
IndexError: list index out of range

Why doesn’t list have a safe “get” method like dictionary?

>>> d = {'a':'b'}
>>> d['a']
'b'
>>> d['c']
KeyError: 'c'
>>> d.get('c', 'fail')
'fail'

>>> l = [1]
>>> l[10]
IndexError: list index out of range

回答 0

最终,它可能没有一个安全的.get方法,因为a dict是一个关联集合(值与名称相关联),在这种情况下,检查键是否存在(并返回其值)而不抛出异常是非常低效的,而这是非常琐碎的避免异常访问列表元素(因为该len方法非常快)。该.get方法允许您查询与名称关联的值,而不直接访问字典中的第37个项目(这更像是您要查询的列表中的内容)。

当然,您可以自己轻松实现此目的:

def safe_list_get (l, idx, default):
  try:
    return l[idx]
  except IndexError:
    return default

您甚至可以在中将其Monkey修补到__builtins__.list构造函数上__main__,但是由于大多数代码不使用它,因此更改的普及程度较小。如果您只想将此代码与自己的代码创建的列表一起使用,则可以简单地子类化list并添加get方法。

Ultimately it probably doesn’t have a safe .get method because a dict is an associative collection (values are associated with names) where it is inefficient to check if a key is present (and return its value) without throwing an exception, while it is super trivial to avoid exceptions accessing list elements (as the len method is very fast). The .get method allows you to query the value associated with a name, not directly access the 37th item in the dictionary (which would be more like what you’re asking of your list).

Of course, you can easily implement this yourself:

def safe_list_get (l, idx, default):
  try:
    return l[idx]
  except IndexError:
    return default

You could even monkeypatch it onto the __builtins__.list constructor in __main__, but that would be a less pervasive change since most code doesn’t use it. If you just wanted to use this with lists created by your own code you could simply subclass list and add the get method.


回答 1

如果您想要第一个元素,例如 my_list.get(0)

>>> my_list = [1,2,3]
>>> next(iter(my_list), 'fail')
1
>>> my_list = []
>>> next(iter(my_list), 'fail')
'fail'

我知道这并非您真正要求的,但可能会帮助其他人。

This works if you want the first element, like my_list.get(0)

>>> my_list = [1,2,3]
>>> next(iter(my_list), 'fail')
1
>>> my_list = []
>>> next(iter(my_list), 'fail')
'fail'

I know it’s not exactly what you asked for but it might help others.


回答 2

可能是因为它对列表语义没有多大意义。但是,您可以通过子类化轻松创建自己的类。

class safelist(list):
    def get(self, index, default=None):
        try:
            return self.__getitem__(index)
        except IndexError:
            return default

def _test():
    l = safelist(range(10))
    print l.get(20, "oops")

if __name__ == "__main__":
    _test()

Probably because it just didn’t make much sense for list semantics. However, you can easily create your own by subclassing.

class safelist(list):
    def get(self, index, default=None):
        try:
            return self.__getitem__(index)
        except IndexError:
            return default

def _test():
    l = safelist(range(10))
    print l.get(20, "oops")

if __name__ == "__main__":
    _test()

回答 3

代替使用.get,这样使用列表应该可以。只是用法上的差异。

>>> l = [1]
>>> l[10] if 10 < len(l) else 'fail'
'fail'

Instead of using .get, using like this should be ok for lists. Just a usage difference.

>>> l = [1]
>>> l[10] if 10 < len(l) else 'fail'
'fail'

回答 4

试试这个:

>>> i = 3
>>> a = [1, 2, 3, 4]
>>> next(iter(a[i:]), 'fail')
4
>>> next(iter(a[i + 1:]), 'fail')
'fail'

Try this:

>>> i = 3
>>> a = [1, 2, 3, 4]
>>> next(iter(a[i:]), 'fail')
4
>>> next(iter(a[i + 1:]), 'fail')
'fail'

回答 5

jose.angel.jimenez


对于“单线”粉丝…


如果需要列表的第一个元素,或者如果列表为空,则需要默认值,请尝试:

liste = ['a', 'b', 'c']
value = (liste[0:1] or ('default',))[0]
print(value)

退货 a

liste = []
value = (liste[0:1] or ('default',))[0]
print(value)

退货 default


其他元素的示例…

liste = ['a', 'b', 'c']
print(liste[0:1])  # returns ['a']
print(liste[1:2])  # returns ['b']
print(liste[2:3])  # returns ['c']

默认回退…

liste = ['a', 'b', 'c']
print((liste[0:1] or ('default',))[0])  # returns a
print((liste[1:2] or ('default',))[0])  # returns b
print((liste[2:3] or ('default',))[0])  # returns c

经过测试 Python 3.6.0 (v3.6.0:41df79263a11, Dec 22 2016, 17:23:13)

Credits to jose.angel.jimenez and Gus Bus.


For the “oneliner” fans…


If you want the first element of a list or if you want a default value if the list is empty try:

liste = ['a', 'b', 'c']
value = (liste[0:1] or ('default',))[0]
print(value)

returns a

and

liste = []
value = (liste[0:1] or ('default',))[0]
print(value)

returns default


Examples for other elements…

liste = ['a', 'b', 'c']
print(liste[0:1])  # returns ['a']
print(liste[1:2])  # returns ['b']
print(liste[2:3])  # returns ['c']
print(liste[3:4])  # returns []

With default fallback…

liste = ['a', 'b', 'c']
print((liste[0:1] or ('default',))[0])  # returns a
print((liste[1:2] or ('default',))[0])  # returns b
print((liste[2:3] or ('default',))[0])  # returns c
print((liste[3:4] or ('default',))[0])  # returns default

Possibly shorter:

liste = ['a', 'b', 'c']
value, = liste[:1] or ('default',)
print(value)  # returns a

It looks like you need the comma before the equal sign, the equal sign and the latter parenthesis.


More general:

liste = ['a', 'b', 'c']
f = lambda l, x, d: l[x:x+1] and l[x] or d
print(f(liste, 0, 'default'))  # returns a
print(f(liste, 1, 'default'))  # returns b
print(f(liste, 2, 'default'))  # returns c
print(f(liste, 3, 'default'))  # returns default

Tested with Python 3.6.0 (v3.6.0:41df79263a11, Dec 22 2016, 17:23:13)


回答 6

最好的办法是将列表转换成字典,然后使用get方法访问它:

>>> my_list = ['a', 'b', 'c', 'd', 'e']
>>> my_dict = dict(enumerate(my_list))
>>> print my_dict
{0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e'}
>>> my_dict.get(2)
'c'
>>> my_dict.get(10, 'N/A')

The best thing you can do is to convert the list into a dict and then access it with the get method:

>>> my_list = ['a', 'b', 'c', 'd', 'e']
>>> my_dict = dict(enumerate(my_list))
>>> print my_dict
{0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e'}
>>> my_dict.get(2)
'c'
>>> my_dict.get(10, 'N/A')

回答 7

因此,我对此进行了更多研究,结果发现没有任何针对此的东西。当我找到list.index(value)时,我感到很兴奋,它返回指定项目的索引,但是没有什么可用于获取特定索引处的值的。因此,如果您不想使用safe_list_get解决方案,我认为这是相当不错的。以下是一些liner if语句,这些语句可以根据情况为您完成工作:

>>> x = [1, 2, 3]
>>> el = x[4] if len(x) > 4 else 'No'
>>> el
'No'

您也可以使用None代替’No’,这更有意义。

>>> x = [1, 2, 3]
>>> i = 2
>>> el_i = x[i] if len(x) == i+1 else None

另外,如果您只想获取列表中的第一项或最后一项,则可以使用

end_el = x[-1] if x else None

您也可以将它们变成函数,但我仍然喜欢IndexError异常解决方案。我尝试了该safe_list_get解决方案的简化版本,并使其变得更简单(没有默认设置):

def list_get(l, i):
    try:
        return l[i]
    except IndexError:
        return None

还没有进行基准测试以了解最快的方法。

So I did some more research into this and it turns out there isn’t anything specific for this. I got excited when I found list.index(value), it returns the index of a specified item, but there isn’t anything for getting the value at a specific index. So if you don’t want to use the safe_list_get solution which I think is pretty good. Here are some 1 liner if statements that can get the job done for you depending on the scenario:

>>> x = [1, 2, 3]
>>> el = x[4] if len(x) > 4 else 'No'
>>> el
'No'

You can also use None instead of ‘No’, which makes more sense.:

>>> x = [1, 2, 3]
>>> i = 2
>>> el_i = x[i] if len(x) == i+1 else None

Also if you want to just get the first or last item in the list, this works

end_el = x[-1] if x else None

You can also make these into functions but I still liked the IndexError exception solution. I experimented with a dummied down version of the safe_list_get solution and made it a bit simpler (no default):

def list_get(l, i):
    try:
        return l[i]
    except IndexError:
        return None

Haven’t benchmarked to see what is fastest.


回答 8

字典用于查找。询问条目是否存在是很有意义的。列表通常是迭代的。通常不问L [10]是否存在,而是问L的长度是否为11。

Dictionaries are for look ups. It makes sense to ask if an entry exists or not. Lists are usually iterated. It isn’t common to ask if L[10] exists but rather if the length of L is 11.


回答 9

您的用例基本上只与固定长度的数组和矩阵有关,这样您就可以知道它们有多长时间。在这种情况下,通常还需要在手动将它们填充为None或0之前创建它们,以便实际上您将使用的任何索引都已经存在。

你可以这样说:我经常在字典上需要.get()。作为一名全职程序员十年后,我认为我从不需要它了。:)

Your usecase is basically only relevant for when doing arrays and matrixes of a fixed length, so that you know how long they are before hand. In that case you typically also create them before hand filling them up with None or 0, so that in fact any index you will use already exists.

You could say this: I need .get() on dictionaries quite often. After ten years as a full time programmer I don’t think I have ever needed it on a list. :)