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


88

为什么不'example'[999:9999]导致错误?既然如此'example'[9],其背后的动机是什么?

从这种行为,我可以假设它'example'[3]本质上/内部与并不相同'example'[3:4],即使两者都导致相同的'm'字符串。


17
[999:9999]不是索引,而是切片,并且具有不同的语义。在python简介中:“退化切片索引得到了妥善处理:太大的索引将替换为字符串大小,上限小于下限则返回一个空字符串。”
Wooble 2012年

2
@Wooble这是实际答案
jondavidjohn 2012年

2
@Wooble你知道为什么会这样吗?感谢您的澄清。
ijverig

为什么?您必须问Guido,但我认为能够假设切片始终与原始序列(我本人)的序列类型相同是很优雅的。
Wooble 2012年

1
@Lapinot是,我编写了依赖此行为的代码。不幸的是,我不记得确切的代码,所以我不能告诉你原因。可能与子字符串有关;有时候,获取空字符串可能正是您想要的。
Mark Ransom '18

Answers:


68

没错!'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的答案。)


1
超出范围的索引可以返回None而不是错误输出-当您什么也没要返回时,这是Python的常规约定。
马克·兰瑟姆

8
@MarkRansom,是的;但是None在这种情况下返回,将很难区分出越界索引和None列表中的值。但是即使有解决方法,对我来说仍然很清楚,在给定越界切片时,返回空序列是正确的事情。这类似于执行两个不相交集的并集。
senderle'2

为了清楚起见,我并不是说你错了。我None在列表中看到了您关于值的观点。
马克·兰瑟姆

1
@MarkRansom,我知道-如果您听起来很防御,对不起。真的,我只是想借口引用集合论:)。
senderle '02

4
噢,除了我说的是“联盟”而不是“交叉点”。
senderle 2014年

31

为了添加一个答案,该答案指向文档中的可靠部分:

给定一个切片表达式s[i:j:k]

的切片小号Ĵ与步骤ķ被定义为物品的索引序列x = i + n*k,使得0 <= n < (j-i)/k。换句话说,在指数ii+ki+2*ki+3*k等等,停车时Ĵ达到(但绝不包括Ĵ)。k为正时,ij减小到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

@Chris_Rands当k为正时,Python会缩放ij使其适合序列的范围。在您的示例中,s[-100:2] == s[0:2]== s[-len(s):2],顺便说一下)。同样,s[-100:100] == s[0:2]
tylerc0816

很好,谢谢。这是对@speedplane上面评论的更好回应。
senderle '18

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.