在Python中获取超出范围的索引默认值[重复]

Posted

技术标签:

【中文标题】在Python中获取超出范围的索引默认值[重复]【英文标题】:Getting a default value on index out of range in Python [duplicate] 【发布时间】:2011-02-04 04:50:51 【问题描述】:
a=['123','2',4]
b=a[4] or 'sss'
print b

我想在列表索引超出范围时获取默认值(此处为:'sss')。

我该怎么做?

【问题讨论】:

【参考方案1】:

本着“请求宽恕,而不是许可”的 Python 精神,这里有一种方法:

try:
    b = a[4]
except IndexError:
    b = 'sss'

【讨论】:

任何简单的方法?? @zjm:这简单的方法 有必要跨越成3个答案吗? @KennyTM:它们是三个不同的选项。我想,这样最好的答案就可以被投票给最高的答案,而糟糕的答案就会被遗忘。这不是为了引诱,实际上是公认的做法:meta.stackexchange.com/questions/21761/… 我想在列表中也看到 dicts 的 .get 方法,当你使用 get 并且它不存在时,它默认返回 None。【参考方案2】:
try:
    b = a[4]
except IndexError:
    b = 'sss'

一种更简洁的方式(仅当您使用字典时才有效):

b = a.get(4,"sss") # exact same thing as above

这是您可能喜欢的另一种方式(同样,仅适用于 dicts):

b = a.setdefault(4,"sss") # if a[4] exists, returns that, otherwise sets a[4] to "sss" and returns "sss"

【讨论】:

您应该为except: 定义例外。例如,当变量a 未定义时,也会触发您的异常。 @Goose:空的except 是邪恶的。最好说except IndexError @shakov, @Eli Bendersky:你是对的。固定。【参考方案3】:

使用 try/catch?

try:
    b=a[4]
except IndexError:
    b='sss'

【讨论】:

【参考方案4】:

本着“请求许可,而不是宽恕”的非 Python 精神,这里有另一种方式:

b = a[4] if len(a) > 4 else 'sss'

【讨论】:

正在使用它,很高兴看到可靠性得到证实。我倾向于尽可能避免尝试(和捕捉)。 为什么要避免 try/catch? 在 Python 中针对引发异常进行优化的唯一技术用例是当happypath 导致引发异常时。 (例如,如果 len(a) 很少 > 4,那么使用 if/then 会更便宜。)。如果happypath 是len(a) > 4,那么使用上述代码的唯一真正原因是更短的代码(有降低可读性的风险),但是maep 使用切片的答案甚至更短......【参考方案5】:

您还可以为这些情况定义一个小辅助函数:

def default(x, e, y):
    try:
        return x()
    except e:
        return y

它返回函数x的返回值,除非它引发了e类型的异常;在这种情况下,它返回值y。用法:

b = default(lambda: a[4], IndexError, 'sss')

编辑:让它只捕获一种指定类型的异常。

仍然欢迎提出改进建议!

【讨论】:

@Thomas:恕我直言,这很不雅,而且引人注目的 except 令人担忧 在邮件列表上有一个关于这样的结构的讨论:mail.python.org/pipermail/python-dev/2009-August/091039.html 旧答案,但仍然如此。 Python 是少数将异常视为好事的语言之一。它通常用于创建可读性的流控制。【参考方案6】:

我完全赞成请求许可(即我不喜欢 try...except 方法)。但是,将代码封装在方法中时会变得更加简洁:

def get_at(array, index, default):
    if index < 0: index += len(array)
    if index < 0: raise IndexError('list index out of range')
    return array[index] if index < len(a) else default

b = get_at(a, 4, 'sss')

【讨论】:

mylist[-1] 应该只获取最后一个元素,但是您的“请求许可”get_at 代码不会表现得像那样。这表明“请求许可”只是错误理念的众多原因之一:您正在检查的内容可能与系统将执行的内容不匹配。即,您不仅系统地尝试重复系统为您完成的工作,而且您很容易将那些额外的重复工作弄错。 “请求宽恕”要好得多 @Alex:很好,没想到。 Python 强大的列表切片语法使这稍微复杂了一点……然而,我不同意你从这种特殊情况下的推断,即“请求宽恕”通常是好的。我当然有偏见,因为我是静态类型的大力支持者。但无论如何,这只是错误的结论。一个更好的结论是我的需求分析不够充分(并且也许没有好的方法可以在没有代码重复或错误触发的情况下以可修改的方式获取内部行为。这表明 API 不好) . 如果你这样做def get_at(array, index, default): try: return array[index] except IndexError: return default,你可以侥幸逃脱 @voyager:我知道这一点。但正如我在第一句话中所说,我反对故意触发异常。我更喜欢显式而不是隐式,因为它减少了混淆的来源(以及由此产生的错误),这意味着密切关注我的方法可以做什么和不能做什么。【参考方案7】:

由于这是谷歌的热门搜索,可能还值得一提的是,标准的“collections”包有一个“defaultdict”,它为这个问题提供了更灵活的解决方案。

你可以做一些整洁的事情,例如:

twodee = collections.defaultdict(dict)
twodee["the horizontal"]["the vertical"] = "we control"

阅读更多:http://docs.python.org/2/library/collections.html

【讨论】:

【参考方案8】:

您可以创建自己的列表类:

class MyList(list):
    def get(self, index, default=None):
        return self[index] if len(self) > index else default

你可以这样使用它:

>>> l = MyList(['a', 'b', 'c'])
>>> l.get(1)
'b'
>>> l.get(9, 'no')
'no'

【讨论】:

【参考方案9】:

对于您想要第一个元素的常见情况,您可以这样做

next(iter([1, 2, 3]), None)

我用它来“解包”一个列表,可能是在过滤它之后。

next((x for x in [1, 3, 5] if x % 2 == 0), None)

cur.execute("SELECT field FROM table")
next(cur.fetchone(), None)

【讨论】:

【参考方案10】:

在 Python 中,美胜于丑

代码高尔夫方法,使用切片和解包(不确定这在 4 年前是否有效,但它在 python 2.7 + 3.3 中)

b,=a[4:5] or ['sss']

比包装函数或 try-catch 恕我直言更好,但对初学者来说很吓人。就我个人而言,我发现元组解包比列表更性感[#]

使用切片而不拆包:

b = a[4] if a[4:] else 'sss'

或者,如果您必须经常这样做,并且不介意制作字典

d = dict(enumerate(a))
b=d.get(4,'sss')

【讨论】:

如果列表超过 5 个元素,您的第一个示例将不起作用。与a[4:5] 一起使用不再好...... using splicing without unpacking 对我有用,否则返回的元素是大小为 1 的列表,而不是标量。 为什么你的第一个答案有额外的逗号?在python解释器中玩:b,=a[4:] or 'sss',b=a[4:] or 'sss'一样 @north.mister 没有。尝试使用 6 个元素的 a,您将在 b 中获得 2 个元素。 我认为不依赖于输入列表的长度,我们可以这样做b, = a[-1:] or ['default value']【参考方案11】:

另一种方式:

b = (a[4:]+['sss'])[0]

【讨论】:

好的,所以我喜欢不冗长。你能解释一下语法吗? a[4:] 从(包括)索引 4 创建一个元素列表。这会导致一个空列表。 [1, 2, 3][999:] == [] 切片操作就是这样。如果 a['123', '2', 4, 5, 6],它将返回 [5, 6] 。然后他添加元素“sss”,创建一个新列表,在本例中为['sss']。最后一步[0] 只取第一个元素,因此返回'sss',但如果有这样一个元素,则会返回a[4]` 实现这一目标的有趣方式。有点不可读。 这是它至少在 Python 3.5 中工作的唯一方式。出于某种原因,在 else 'default value' 中调用 a[4] if 4 总是返回默认值。但非常有趣的是,切片总是返回一个列表(甚至是空的)。谢谢亚历克斯! 4 in a 询问4 是否在列表中作为值,而不是键!【参考方案12】:

如果您正在寻找一种可维护的方法来获取索引运算符的默认值,我发现以下方法很有用:

如果您从 operator 模块覆盖 operator.getitem 以添加可选的默认参数,您将获得与原始参数相同的行为,同时保持向后兼容性。

def getitem(iterable, index, default=None):
  import operator
  try:
    return operator.getitem(iterable, index)
  except IndexError:
    return default

【讨论】:

【参考方案13】:

如果您正在寻找减少字符长度的快速技巧,您可以试试这个。

a=['123','2',4]
a.append('sss') #Default value
n=5 #Index you want to access
max_index=len(a)-1
b=a[min(max_index, n)]
print(b)

但是这个技巧只有在你不想再修改列表时才有用

【讨论】:

以上是关于在Python中获取超出范围的索引默认值[重复]的主要内容,如果未能解决你的问题,请参考以下文章

在python IndexError中使用for循环反转字符串:字符串索引超出范围[重复]

(Python)列表索引超出范围-迭代[重复]

索引超出了数组拆分函数的范围[重复]

设置UIPickerView的默认值:索引超出范围

线程 1:致命错误:索引超出范围。没有快速从数组中获取值,控制台显示它们不是空数组

如何在 python 3.4 tkinter“索引错误:列表索引超出范围”中修复此错误