为啥索引超出范围的子字符串切片有效?

Posted

技术标签:

【中文标题】为啥索引超出范围的子字符串切片有效?【英文标题】:Why does substring slicing with index out of range work?为什么索引超出范围的子字符串切片有效? 【发布时间】:2019-06-15 21:13:03 【问题描述】:

为什么'example'[999:9999] 不会导致错误?既然'example'[9]做到了,那背后的动机是什么?

根据这种行为,我可以假设 'example'[3] 在本质上/在内部与 'example'[3:4] 不同,即使两者都产生相同的 'm' 字符串。

【问题讨论】:

[999:9999] 不是索引,而是切片,并且具有不同的语义。从 python 介绍:“退化的切片索引被优雅地处理:一个太大的索引被字符串大小替换,一个小于下限的上限返回一个空字符串。” @Wooble 是实际答案 @Wooble 你知道为什么会这样吗?感谢您的澄清。 为什么?你得问 Guido,但我认为能够假设一个片段总是与原始序列相同类型的序列,我自己。 @Lapinot 是的,我编写了依赖于这种行为的代码。不幸的是,我不记得确切的代码,所以我不能告诉你为什么。可能与子字符串有关;有时,获得一个空字符串可能正是您想要的。 【参考方案1】:

你是对的! 'example'[3:4]'example'[3] 根本不同,在序列边界之外切片(至少对于内置函数)不会导致错误。

一开始可能会令人惊讶,但仔细想想,它就很有意义。索引返回单个项目,但切片返回项目的子序列。因此,当您尝试索引一个不存在的值时,没有什么可以返回。但是当你对一个超出边界的序列进行切片时,你仍然可以返回一个空序列。

这里令人困惑的部分原因是字符串的行为与列表略有不同。看看当你对一个列表做同样的事情时会发生什么:

>>> [0, 1, 2, 3, 4, 5][3]
3
>>> [0, 1, 2, 3, 4, 5][3:4]
[3]

这里的区别很明显。在字符串的情况下,结果似乎是相同的,因为在 Python 中,没有字符串之外的单个字符这样的东西。单个字符只是一个 1 字符的字符串。

(有关在序列范围之外进行切片的确切语义,请参阅mgilson's answer。)

【讨论】:

超出范围的索引可能会返回 None 而不是出错 - 这是 Python 的惯例,当您没有返回任何内容时。 @MarkRansom,这是真的;但是在这种情况下返回 None 会更难区分越界索引和列表中的 None 值。但即使有一种解决方法,我仍然很清楚,当给定一个越界切片时,返回一个空序列是正确的做法。这类似于执行两个不相交集的并集。 澄清一下,我没有说你错了。我在列表中看到了您关于 None 值的观点。 @MarkRansom,我知道 - 抱歉,如果我听起来很防御。真的,我只是想找个借口来引用集合论:)。 噢,除了我说的是“联合”而不是“交叉点”。【参考方案2】:

为了在documentation 中添加指向稳健部分的答案:

给定一个像s[i:j:k]这样的切片表达式,

ijs 切片,步骤为 k 被定义为具有索引x = i + n*k 使得0 <= n < (j-i)/k。换句话说,索引是ii+ki+2*ki+3*k 等等,在达到 j 时停止(但从不包括 j )。 k 为正时,如果 ij 更大,则将它们归约为 len(s)

如果你写s[999:9999],python 将返回s[len(s):len(s)],因为len(s) < 999 并且你的步骤是肯定的(1 - 默认值)。

【讨论】:

大概当k为正时,ij在较小的时候也增加到-len(s)?例如s = 'bac'; s[-100:2] == s[-len(s):2] @Chris_Rands 当k 为正时,Python 将缩放ij 以使它们适合序列的边界。在您的示例中,s[-100:2] == s[0:2](顺便说一句,== s[-len(s):2])。同样,s[-100:100] == s[0:2]. 很好,谢谢。这是对@speedplane 上述评论的更好回应。【参考方案3】:

切片不受内置类型的边界检查。尽管您的两个示例似乎具有相同的结果,但它们的工作方式不同;用一个列表来试试。

【讨论】:

以上是关于为啥索引超出范围的子字符串切片有效?的主要内容,如果未能解决你的问题,请参考以下文章

Python中偶尔遇到的细节疑问:去除列名特殊字符标准差出现nan切片索引可超出范围range步长

表格视图单元格中的 uicollectionview 出现错误:索引超出范围,为啥?

当切片索引超出范围时如何引发 IndexError?

python 列表,元组,字符串 切片 超出索引值不报错

从firebase删除时数组索引超出范围

IndexError:列表索引超出范围 - python 错误