为啥索引超出范围的子字符串切片有效?
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]
这样的切片表达式,
从 i 到 j 的 s 切片,步骤为 k 被定义为具有索引
x = i + n*k
使得0 <= n < (j-i)/k
。换句话说,索引是i
、i+k
、i+2*k
、i+3*k
等等,在达到 j 时停止(但从不包括 j )。 当 k 为正时,如果 i 和 j 更大,则将它们归约为len(s)
如果你写s[999:9999]
,python 将返回s[len(s):len(s)]
,因为len(s) < 999
并且你的步骤是肯定的(1
- 默认值)。
【讨论】:
大概当k
为正时,i
和j
在较小的时候也增加到-len(s)
?例如s = 'bac'; s[-100:2] == s[-len(s):2]
@Chris_Rands 当k
为正时,Python 将缩放i
和j
以使它们适合序列的边界。在您的示例中,s[-100:2] == s[0:2]
(顺便说一句,== s[-len(s):2]
)。同样,s[-100:100] == s[0:2]
.
很好,谢谢。这是对@speedplane 上述评论的更好回应。【参考方案3】:
切片不受内置类型的边界检查。尽管您的两个示例似乎具有相同的结果,但它们的工作方式不同;用一个列表来试试。
【讨论】:
以上是关于为啥索引超出范围的子字符串切片有效?的主要内容,如果未能解决你的问题,请参考以下文章
Python中偶尔遇到的细节疑问:去除列名特殊字符标准差出现nan切片索引可超出范围range步长